/src/sleuthkit/tsk/fs/fs_io.c
Line | Count | Source |
1 | | /* |
2 | | * The Sleuth Kit |
3 | | * |
4 | | * Brian Carrier [carrier <at> sleuthkit [dot] org] |
5 | | * Copyright (c) 2006-2011 Brian Carrier, Basis Technology. All Rights reserved |
6 | | * Copyright (c) 2003-2005 Brian Carrier. All rights reserved |
7 | | * |
8 | | * Copyright (c) 1997,1998,1999, International Business Machines |
9 | | * Corporation and others. All Rights Reserved. |
10 | | * |
11 | | * |
12 | | * LICENSE |
13 | | * This software is distributed under the IBM Public License. |
14 | | * AUTHOR(S) |
15 | | * Wietse Venema |
16 | | * IBM T.J. Watson Research |
17 | | * P.O. Box 704 |
18 | | * Yorktown Heights, NY 10598, USA |
19 | | --*/ |
20 | | |
21 | | /** \file fs_io.c |
22 | | * Contains functions to read data from a disk image and wrapper functions to read file content. |
23 | | */ |
24 | | |
25 | | #include <errno.h> |
26 | | |
27 | | #include "tsk/pool/tsk_pool.h" |
28 | | |
29 | | #include "tsk_fs_i.h" |
30 | | #include "encryptionHelper.h" |
31 | | |
32 | | |
33 | | /** \internal |
34 | | * Internal method to deal with calculating correct offset when we have pre and post bytes |
35 | | * in teh file system blocks (i.e. RAW Cds) |
36 | | * @param a_fs File system being analyzed |
37 | | * @param a_off Byte offset into file system (i.e. not offset into image) |
38 | | * @param a_buf Buffer to write data into |
39 | | * @param a_len Number of bytes to read |
40 | | * @returns Number of bytes read or -1 on error |
41 | | */ |
42 | | static ssize_t |
43 | | fs_prepost_read(TSK_FS_INFO * a_fs, TSK_OFF_T a_off, char *a_buf, |
44 | | size_t a_len) |
45 | 661k | { |
46 | 661k | TSK_OFF_T cur_off = a_off; |
47 | 661k | TSK_OFF_T end_off = a_off + a_len; |
48 | 661k | ssize_t cur_idx = 0; |
49 | | |
50 | | // we need to read block by block so that we can skip the needed pre and post bytes |
51 | 2.37M | while (cur_off < end_off) { |
52 | 1.71M | TSK_OFF_T read_off; |
53 | 1.71M | ssize_t retval2 = 0; |
54 | 1.71M | TSK_DADDR_T blk = cur_off / a_fs->block_size; |
55 | 1.71M | size_t read_len = a_fs->block_size - cur_off % a_fs->block_size; |
56 | | |
57 | 1.71M | if ((TSK_OFF_T)read_len > end_off - cur_off) |
58 | 531k | read_len = (size_t) (end_off - cur_off); |
59 | | |
60 | 1.71M | read_off = |
61 | 1.71M | a_fs->offset + cur_off + blk * (a_fs->block_pre_size + |
62 | 1.71M | a_fs->block_post_size) + a_fs->block_pre_size; |
63 | 1.71M | if (tsk_verbose) |
64 | 0 | fprintf(stderr, |
65 | 0 | "fs_prepost_read: Mapped %" PRIdOFF " to %" PRIdOFF "\n", |
66 | 0 | cur_off, read_off); |
67 | | |
68 | 1.71M | retval2 = |
69 | 1.71M | tsk_img_read(a_fs->img_info, read_off, &a_buf[cur_idx], |
70 | 1.71M | read_len); |
71 | 1.71M | if (retval2 == -1) |
72 | 2.27k | return -1; |
73 | 1.71M | else if (retval2 == 0) |
74 | 0 | break; |
75 | 1.71M | cur_idx += retval2; |
76 | 1.71M | cur_off += retval2; |
77 | 1.71M | } |
78 | 658k | return cur_idx; |
79 | 661k | } |
80 | | |
81 | | /** |
82 | | * \ingroup fslib |
83 | | * Read arbitrary data from inside of the file system. |
84 | | * @param a_fs The file system handle. |
85 | | * @param a_off The byte offset to start reading from (relative to start of file system) |
86 | | * @param a_buf The buffer to store the block in. |
87 | | * @param a_len The number of bytes to read |
88 | | * @return The number of bytes read or -1 on error. |
89 | | */ |
90 | | ssize_t |
91 | | tsk_fs_read(TSK_FS_INFO * a_fs, TSK_OFF_T a_off, char *a_buf, size_t a_len) |
92 | 10.4M | { |
93 | 10.4M | return tsk_fs_read_decrypt(a_fs, a_off, a_buf, a_len, 0); |
94 | 10.4M | } |
95 | | /** |
96 | | * \ingroup fslib |
97 | | * Read arbitrary data from inside of the file system. |
98 | | * @param a_fs The file system handle. |
99 | | * @param a_off The byte offset to start reading from (relative to start of file system) |
100 | | * @param a_buf The buffer to store the block in. |
101 | | * @param a_len The number of bytes to read |
102 | | * @param crypto_id Starting block number needed for the XTS IV |
103 | | * @return The number of bytes read or -1 on error. |
104 | | */ |
105 | | ssize_t |
106 | | tsk_fs_read_decrypt(TSK_FS_INFO * a_fs, TSK_OFF_T a_off, char *a_buf, size_t a_len, |
107 | | TSK_DADDR_T crypto_id) |
108 | 11.4M | { |
109 | | // do a sanity check on the read bounds, but only if the block |
110 | | // value has been set. |
111 | | // note that this could prevent us from viewing the FS slack... |
112 | 11.4M | if ((a_fs->last_block_act > 0) |
113 | 8.47M | && ((TSK_DADDR_T) a_off >= |
114 | 8.47M | ((a_fs->last_block_act + 1) * a_fs->block_size))) { |
115 | 167k | tsk_error_reset(); |
116 | 167k | tsk_error_set_errno(TSK_ERR_FS_READ); |
117 | 167k | if ((TSK_DADDR_T) a_off < |
118 | 167k | ((a_fs->last_block + 1) * a_fs->block_size)) |
119 | 155k | tsk_error_set_errstr |
120 | 155k | ("tsk_fs_read: Offset missing in partial image: %" |
121 | 155k | PRIuDADDR ")", a_off); |
122 | 11.6k | else |
123 | 11.6k | tsk_error_set_errstr |
124 | 11.6k | ("tsk_fs_read: Offset is too large for image: %" PRIuDADDR |
125 | 11.6k | ")", a_off); |
126 | 167k | return -1; |
127 | 167k | } |
128 | | |
129 | | // We need different logic for encrypted file systems |
130 | 11.3M | if ((a_fs->flags & TSK_FS_INFO_FLAG_ENCRYPTED) && a_fs->block_size) { |
131 | | // If we're reading on block boundaries and a multiple of block |
132 | | // sizes, we can just decrypt directly to the buffer. |
133 | 0 | if ((a_off % a_fs->block_size == 0) && (a_len % a_fs->block_size == 0)) { |
134 | 0 | return tsk_fs_read_block_decrypt(a_fs, a_off / a_fs->block_size, a_buf, a_len, crypto_id); |
135 | 0 | } |
136 | | |
137 | | // Since we can only decrypt on block boundaries, we'll need to |
138 | | // decrypt the blocks and then copy to the output buffer. |
139 | | |
140 | | // Starting address needs to be aligned by block size; |
141 | 0 | TSK_OFF_T bit_magic = a_fs->block_size - 1; |
142 | 0 | TSK_OFF_T start = a_off & ~bit_magic; |
143 | | |
144 | | // Ending address needs to be rounded up to the nearest |
145 | | // block boundary. |
146 | 0 | TSK_OFF_T end = (a_off + a_len + bit_magic) & ~bit_magic; |
147 | 0 | TSK_OFF_T len = end - start; |
148 | | |
149 | | // Decrypt the blocks to a temp buffer |
150 | 0 | char * temp_buffer = tsk_malloc(len); |
151 | 0 | if (temp_buffer == NULL) { |
152 | 0 | return -1; |
153 | 0 | } |
154 | | |
155 | 0 | if (tsk_fs_read_block_decrypt(a_fs, start / a_fs->block_size, temp_buffer, |
156 | 0 | len, crypto_id) != len) { |
157 | 0 | free(temp_buffer); |
158 | 0 | return -1; |
159 | 0 | } |
160 | | |
161 | | // Copy the decrypted data |
162 | 0 | memcpy(a_buf, temp_buffer + a_off - start, a_len); |
163 | |
|
164 | 0 | free(temp_buffer); |
165 | |
|
166 | 0 | return a_len; |
167 | 0 | } |
168 | | |
169 | 11.3M | if (((a_fs->block_pre_size) || (a_fs->block_post_size)) |
170 | 661k | && (a_fs->block_size)) { |
171 | 661k | return fs_prepost_read(a_fs, a_off, a_buf, a_len); |
172 | 661k | } |
173 | 10.6M | else { |
174 | 10.6M | return tsk_img_read(a_fs->img_info, a_off + a_fs->offset, a_buf, |
175 | 10.6M | a_len); |
176 | 10.6M | } |
177 | 11.3M | } |
178 | | |
179 | | /** |
180 | | * \ingroup fslib |
181 | | * Read a file system block into a char* buffer. |
182 | | * This is actually a wrapper around the fs_read_random function, |
183 | | * but it allows the starting location to be specified as a block address. |
184 | | * |
185 | | * @param a_fs The file system structure. |
186 | | * @param a_addr The starting block file system address. |
187 | | * @param a_buf The char * buffer to store the block data in. |
188 | | * @param a_len The number of bytes to read (must be a multiple of the block size) |
189 | | * @return The number of bytes read or -1 on error. |
190 | | */ |
191 | | ssize_t |
192 | | tsk_fs_read_block(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr, char *a_buf, |
193 | | size_t a_len) |
194 | 54.0k | { |
195 | 54.0k | return tsk_fs_read_block_decrypt(a_fs, a_addr, a_buf, a_len, 0); |
196 | 54.0k | } |
197 | | |
198 | | /** |
199 | | * \ingroup fslib |
200 | | * Read a file system block into a char* buffer. |
201 | | * This is actually a wrapper around the fs_read_random function, |
202 | | * but it allows the starting location to be specified as a block address. |
203 | | * |
204 | | * @param a_fs The file system structure. |
205 | | * @param a_addr The starting block file system address. |
206 | | * @param a_buf The char * buffer to store the block data in. |
207 | | * @param a_len The number of bytes to read (must be a multiple of the block size) |
208 | | * @param crypto_id Starting block number needed for the XTS IV |
209 | | * @return The number of bytes read or -1 on error. |
210 | | */ |
211 | | ssize_t |
212 | | tsk_fs_read_block_decrypt(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr, char *a_buf, |
213 | | size_t a_len, TSK_DADDR_T crypto_id) |
214 | 925k | { |
215 | 925k | if (a_len % a_fs->block_size) { |
216 | 0 | tsk_error_reset(); |
217 | 0 | tsk_error_set_errno(TSK_ERR_FS_READ); |
218 | 0 | tsk_error_set_errstr("tsk_fs_read_block: length %" PRIuSIZE "" |
219 | 0 | " not a multiple of %d", a_len, a_fs->block_size); |
220 | 0 | return -1; |
221 | 0 | } |
222 | | |
223 | 925k | if (a_addr > a_fs->last_block_act) { |
224 | 8.95k | tsk_error_reset(); |
225 | 8.95k | tsk_error_set_errno(TSK_ERR_FS_READ); |
226 | 8.95k | if (a_addr <= a_fs->last_block) |
227 | 6.61k | tsk_error_set_errstr |
228 | 6.61k | ("tsk_fs_read_block: Address missing in partial image: %" |
229 | 6.61k | PRIuDADDR ")", a_addr); |
230 | 2.34k | else |
231 | 2.34k | tsk_error_set_errstr |
232 | 2.34k | ("tsk_fs_read_block: Address is too large for image: %" |
233 | 2.34k | PRIuDADDR ")", a_addr); |
234 | 8.95k | return -1; |
235 | 8.95k | } |
236 | | |
237 | | #ifdef HAVE_LIBMBEDTLS |
238 | | if (a_fs->encryption_type == TSK_FS_ENCRYPTION_TYPE_BITLOCKER) { |
239 | | // Bitlocker moves some sectors from the beginning of the volume |
240 | | // to another spot later in the volume in addition to encrypting them, |
241 | | // so we need to use a custom method to read in the encrypted data |
242 | | // and decrypt it. |
243 | | TSK_DADDR_T offsetInVolume = (TSK_DADDR_T)(a_addr) * a_fs->block_size; |
244 | | return read_and_decrypt_bitlocker_blocks(a_fs, offsetInVolume, a_len, a_buf); |
245 | | } |
246 | | #endif |
247 | | |
248 | 916k | ssize_t ret_len; |
249 | 916k | if ((a_fs->block_pre_size == 0) && (a_fs->block_post_size == 0)) { |
250 | 916k | TSK_OFF_T off = |
251 | 916k | a_fs->offset + (TSK_OFF_T) (a_addr) * a_fs->block_size; |
252 | | |
253 | 916k | ret_len = tsk_img_read(a_fs->img_info, off, a_buf, a_len); |
254 | 916k | } |
255 | 0 | else { |
256 | 0 | TSK_OFF_T off = (TSK_OFF_T) (a_addr) * a_fs->block_size; |
257 | 0 | ret_len = fs_prepost_read(a_fs, off, a_buf, a_len); |
258 | 0 | } |
259 | | |
260 | 916k | if ((a_fs->flags & TSK_FS_INFO_FLAG_ENCRYPTED) |
261 | 0 | && ret_len > 0 |
262 | 0 | && a_fs->decrypt_block) { |
263 | 0 | TSK_DADDR_T i; |
264 | 0 | for (i = 0; i < a_len / a_fs->block_size; i++) { |
265 | 0 | a_fs->decrypt_block(a_fs, crypto_id + i, |
266 | 0 | a_buf + (a_fs->block_size * i)); |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | 916k | return ret_len; |
271 | 925k | } |