Coverage Report

Created: 2024-04-23 06:05

/src/sleuthkit/tsk/fs/unix_misc.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The Sleuth Kit 
3
 *
4
 * Brian Carrier [carrier <at> sleuthkit [dot] org]
5
 * Copyright (c) 2008-2011 Brian Carrier.  All Rights reserved
6
 *
7
 * This software is distributed under the Common Public License 1.0
8
 */
9
10
11
/**
12
 * \file unix_misc.c
13
 * Contains code that is common to both UFS1/2 and Ext2/3 file systems. 
14
 */
15
16
#include "tsk_fs_i.h"
17
#include "tsk_ffs.h"
18
#include "tsk_ext2fs.h"
19
20
21
/*********** MAKE DATA RUNS ***************/
22
23
/** \internal
24
 * Process an array of addresses and turn them into runs
25
 *
26
 * @param fs File system to analyze
27
 * @param fs_attr Data attribute to add runs to
28
 * @param addrs Buffer of addresses to process and turn into runs
29
 * @param addr_len Number of addresses in buffer
30
 * @param length Length of file remaining
31
 *
32
 * @returns the number of bytes processed and -1 if an error occurred
33
 */
34
static TSK_OFF_T
35
unix_make_data_run_direct(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr,
36
    TSK_DADDR_T * addrs, size_t addr_len, TSK_OFF_T length)
37
49
{
38
49
    TSK_DADDR_T run_start = 0;
39
49
    TSK_DADDR_T run_len = 0;
40
49
    TSK_DADDR_T blks_processed = 0;
41
49
    size_t i;
42
49
    size_t fs_blen;             // how big is each "block" (in fragments)
43
44
49
    if (addr_len == 0) {
45
0
        return 0;
46
0
    }
47
48
    // block_size is a fragment size in UFS, so we need to maintain length in fragments
49
49
    if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
50
0
        FFS_INFO *ffs = (FFS_INFO *) fs;
51
0
        fs_blen = ffs->ffsbsize_f;
52
0
    }
53
49
    else {
54
49
        fs_blen = 1;
55
49
    }
56
57
49
    run_start = addrs[0];
58
49
    run_len = fs_blen;
59
60
    /* Note that we are lazy about length.  We stop only when a run is past length,
61
     * we do not end exactly at length -- although that should happen anyway.  
62
     */
63
537
    for (i = 0; i < addr_len; i++) {
64
65
        /* Make a new run if:
66
         * - This is the last addresss in the buffer
67
         * - The next address is not part of the current run
68
         * -- special case for sparse since they use 0 as an address
69
         */
70
523
        if ((i + 1 == addr_len) ||
71
523
            ((run_start + run_len != addrs[i + 1]) && (run_start != 0)) ||
72
523
            ((run_start == 0) && (addrs[i + 1] != 0))) {
73
74
357
            TSK_FS_ATTR_RUN *data_run;
75
76
            // make a non-resident run
77
357
            data_run = tsk_fs_attr_run_alloc();
78
357
            if (data_run == NULL)
79
0
                return -1;
80
81
357
            data_run->addr = run_start;
82
357
            data_run->len = run_len;
83
84
357
            if (run_start == 0)
85
81
                data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE;
86
87
            // save the run
88
357
            tsk_fs_attr_append_run(fs, fs_attr, data_run);
89
90
            // get ready for the next run
91
357
            if (i + 1 != addr_len)
92
343
                run_start = addrs[i + 1];
93
357
            run_len = 0;
94
95
            // stop if we are past the length requested
96
357
            if (blks_processed * fs->block_size > (TSK_DADDR_T) length)
97
35
                break;
98
357
        }
99
488
        run_len += fs_blen;
100
488
        blks_processed += fs_blen;
101
488
    }
102
103
49
    return blks_processed * fs->block_size;
104
49
}
105
106
107
/** \internal
108
 * Read an indirect block and process the contents to make a runlist from the pointers. 
109
 *
110
 * @param fs File system to analyze
111
 * @param fs_attr Structure to save run data into
112
 * @param fs_attr_indir Structure to save addresses of indirect block pointers in
113
 * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type)
114
 * @param level Indirection level that this will process at (1+)
115
 * @param addr Address of block to read
116
 * @param length Length of file remaining
117
 *
118
 * @returns the number of bytes processed during call and -1 if an error occurred
119
 */
120
static TSK_OFF_T
121
unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr,
122
    TSK_FS_ATTR * fs_attr_indir, char *buf[], int level, TSK_DADDR_T addr,
123
    TSK_OFF_T length)
124
14
{
125
14
    size_t addr_cnt = 0;
126
14
    TSK_DADDR_T *myaddrs = (TSK_DADDR_T *) buf[level];
127
14
    TSK_OFF_T length_remain = length;
128
14
    TSK_OFF_T retval;
129
14
    size_t fs_bufsize;
130
14
    size_t fs_blen;
131
14
    TSK_FS_ATTR_RUN *data_run;
132
133
14
    if (tsk_verbose)
134
0
        tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", "unix_make_data_run_indirect",
135
0
            level, addr);
136
137
    // block_size is a fragment size in UFS, so we need to maintain length in fragments
138
14
    if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
139
0
        FFS_INFO *ffs = (FFS_INFO *) fs;
140
0
        fs_blen = ffs->ffsbsize_f;
141
0
        fs_bufsize = ffs->ffsbsize_b;
142
0
    }
143
14
    else {
144
14
        fs_blen = 1;
145
14
        fs_bufsize = fs->block_size;
146
14
    }
147
148
14
    if (addr > fs->last_block) {
149
14
        tsk_error_reset();
150
14
        tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
151
14
        tsk_error_set_errstr("unix: Indirect block address too large: %"
152
14
            PRIuDADDR "", addr);
153
14
        return -1;
154
14
    }
155
156
    // make a non-resident run
157
0
    data_run = tsk_fs_attr_run_alloc();
158
0
    if (data_run == NULL)
159
0
        return -1;
160
161
0
    data_run->addr = addr;
162
0
    data_run->len = fs_blen;
163
164
    /*
165
     * Read a block of disk addresses.
166
     */
167
    // sparse
168
0
    if (addr == 0) {
169
0
        memset(buf[0], 0, fs_bufsize);
170
0
        data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE;
171
0
    }
172
0
    else {
173
0
        ssize_t cnt;
174
        // read the data into the scratch buffer
175
0
        cnt = tsk_fs_read_block(fs, addr, buf[0], fs_bufsize);
176
0
        if (cnt != (ssize_t)fs_bufsize) {
177
0
            if (cnt >= 0) {
178
0
                tsk_error_reset();
179
0
                tsk_error_set_errno(TSK_ERR_FS_READ);
180
0
            }
181
0
            tsk_error_set_errstr2("unix_make_data_run_indir: Block %"
182
0
                PRIuDADDR, addr);
183
0
            free(data_run);
184
0
            return -1;
185
0
        }
186
0
    }
187
188
    // save the run
189
0
    tsk_fs_attr_append_run(fs, fs_attr_indir, data_run);
190
191
0
    data_run = NULL;
192
193
    // convert the raw addresses to the correct endian ordering
194
0
    if ((fs->ftype == TSK_FS_TYPE_FFS1)
195
0
        || (fs->ftype == TSK_FS_TYPE_FFS1B)
196
0
        || (TSK_FS_TYPE_ISEXT(fs->ftype))) {
197
0
        size_t n;
198
0
        uint32_t *iaddr = (uint32_t *) buf[0];
199
0
        addr_cnt = fs_bufsize / sizeof(*iaddr);
200
0
        for (n = 0; n < addr_cnt; n++) {
201
0
            myaddrs[n] = tsk_getu32(fs->endian, (uint8_t *) & iaddr[n]);
202
0
        }
203
0
    }
204
0
    else if (fs->ftype == TSK_FS_TYPE_FFS2) {
205
0
        size_t n;
206
0
        uint64_t *iaddr = (uint64_t *) buf[0];
207
0
        addr_cnt = fs_bufsize / sizeof(*iaddr);
208
0
        for (n = 0; n < addr_cnt; n++) {
209
0
            myaddrs[n] = tsk_getu64(fs->endian, (uint8_t *) & iaddr[n]);
210
0
        }
211
0
    }
212
213
    // pass the addresses to the next level
214
0
    if (level == 1) {
215
0
        retval =
216
0
            unix_make_data_run_direct(fs, fs_attr, myaddrs, addr_cnt,
217
0
            length_remain);
218
0
        if (retval != -1) {
219
0
            length_remain -= retval;
220
0
        }
221
0
    }
222
0
    else {
223
0
        size_t i;
224
0
        retval = 0;
225
0
        for (i = 0; i < addr_cnt && retval != -1; i++) {
226
0
            retval =
227
0
                unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir,
228
0
                buf, level - 1, myaddrs[i], length_remain);
229
0
            if (retval == -1) {
230
0
                break;
231
0
            }
232
0
            else {
233
0
                length_remain -= retval;
234
0
            }
235
0
        }
236
0
    }
237
238
0
    if (retval == -1) {
239
0
        return -1;
240
0
    }
241
0
    return length - length_remain;
242
0
}
243
244
245
/** \internal
246
 *
247
 * @returns 1 on error and 0 on success
248
 */
249
uint8_t
250
tsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file)
251
49
{
252
49
    TSK_OFF_T length = 0;
253
49
    TSK_OFF_T read_b = 0;
254
49
    TSK_FS_ATTR *fs_attr;
255
49
    TSK_FS_META *fs_meta = fs_file->meta;
256
49
    TSK_FS_INFO *fs = fs_file->fs_info;
257
258
    // clean up any error messages that are lying around
259
49
    tsk_error_reset();
260
261
49
    if (tsk_verbose)
262
0
        tsk_fprintf(stderr,
263
0
            "unix_make_data_run: Processing file %" PRIuINUM "\n",
264
0
            fs_meta->addr);
265
266
    // see if we have already loaded the runs
267
49
    if ((fs_meta->attr != NULL)
268
49
        && (fs_meta->attr_state == TSK_FS_META_ATTR_STUDIED)) {
269
0
        return 0;
270
0
    }
271
49
    if (fs_meta->attr_state == TSK_FS_META_ATTR_ERROR) {
272
0
        return 1;
273
0
    }
274
275
    // not sure why this would ever happen, but...
276
49
    if (fs_meta->attr != NULL) {
277
0
        tsk_fs_attrlist_markunused(fs_meta->attr);
278
0
    }
279
49
    else {
280
49
        fs_meta->attr = tsk_fs_attrlist_alloc();
281
49
    }
282
283
49
    if ((TSK_FS_TYPE_ISFFS(fs->ftype) == 0)
284
49
        && (TSK_FS_TYPE_ISEXT(fs->ftype) == 0)) {
285
0
        tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
286
0
        tsk_error_set_errstr
287
0
            ("unix_make_run: Called with non-Unix file system: %x",
288
0
            fs->ftype);
289
0
        return 1;
290
0
    }
291
292
49
    length = roundup(fs_meta->size, fs->block_size);
293
294
49
    if ((fs_attr =
295
49
            tsk_fs_attrlist_getnew(fs_meta->attr,
296
49
                TSK_FS_ATTR_NONRES)) == NULL) {
297
0
        return 1;
298
0
    }
299
300
    // initialize the data run
301
49
    if (tsk_fs_attr_set_run(fs_file, fs_attr, NULL, NULL,
302
49
            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
303
49
            fs_meta->size, fs_meta->size, roundup(fs_meta->size,
304
49
                fs->block_size), 0, 0)) {
305
0
        return 1;
306
0
    }
307
308
49
    read_b =
309
49
        unix_make_data_run_direct(fs, fs_attr,
310
49
        (TSK_DADDR_T *) fs_meta->content_ptr, 12, length);
311
49
    if (read_b == -1) {
312
0
        fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
313
0
        if (fs_meta->flags & TSK_FS_META_FLAG_UNALLOC)
314
0
            tsk_error_set_errno(TSK_ERR_FS_RECOVER);
315
0
        return 1;
316
0
    }
317
49
    length -= read_b;
318
319
    /* if there is still data left, read the indirect */
320
49
    if (length > 0) {
321
14
        int level;
322
14
        char *buf[4] = {NULL};
323
14
        size_t fs_bufsize0;
324
14
        size_t fs_bufsize1;
325
14
        size_t ptrsperblock;
326
14
        int numBlocks = 0;
327
14
        int numSingIndirect = 0;
328
14
        int numDblIndirect = 0;
329
14
        int numTripIndirect = 0;
330
14
        TSK_FS_ATTR *fs_attr_indir;
331
332
333
        /* With FFS/UFS a full block contains the addresses, but block_size is
334
         * only a fragment.  Figure out the scratch buffer size and the buffers to 
335
         * store the cleaned addresses (endian converted) */
336
14
        if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
337
0
            FFS_INFO *ffs = (FFS_INFO *) fs;
338
339
0
            fs_bufsize0 = ffs->ffsbsize_b;
340
0
            if ((fs->ftype == TSK_FS_TYPE_FFS1)
341
0
                || (fs->ftype == TSK_FS_TYPE_FFS1B)) {
342
0
                ptrsperblock = fs_bufsize0 / 4;
343
0
            }
344
0
            else {
345
0
                ptrsperblock = fs_bufsize0 / 8;
346
0
            }
347
0
        }
348
14
        else {
349
14
            fs_bufsize0 = fs->block_size;
350
14
            ptrsperblock = fs_bufsize0 / 4;
351
14
        }
352
14
        fs_bufsize1 = sizeof(TSK_DADDR_T) * ptrsperblock;
353
354
        /*
355
         * Initialize a buffer for the 3 levels of indirection that are supported by
356
         * this inode.  Each level of indirection will have a buffer to store
357
         * addresses in.  buf[0] is a special scratch buffer that is used to store
358
         * raw data from the image (before endian conversions are applied).  It is
359
         * equal to one block size.  The others will store TSK_DADDR_T structures
360
         * and will have a size depending on the FS type. 
361
         */
362
14
        if ((fs_attr_indir =
363
14
                tsk_fs_attrlist_getnew(fs_meta->attr,
364
14
                    TSK_FS_ATTR_NONRES)) == NULL) {
365
0
            return 1;
366
0
        }
367
368
        // determine number of indirect lbocks needed for file size...
369
14
        numBlocks =
370
14
            (int) (((fs_meta->size + fs_bufsize0 - 1) / fs_bufsize0) - 12);
371
14
        numSingIndirect =
372
14
            (int) ((numBlocks + ptrsperblock - 1) / ptrsperblock);
373
14
        numDblIndirect = 0;
374
14
        numTripIndirect = 0;
375
376
        // double block pointer?
377
14
        if (numSingIndirect > 1) {
378
14
            numDblIndirect = (int)
379
14
                ((numSingIndirect - 1 + ptrsperblock - 1) / ptrsperblock);
380
14
            if (numDblIndirect > 1) {
381
14
                numTripIndirect = (int)
382
14
                    ((numDblIndirect - 1 + ptrsperblock -
383
14
                        1) / ptrsperblock);
384
14
            }
385
14
        }
386
387
        // initialize the data run
388
14
        if (tsk_fs_attr_set_run(fs_file, fs_attr_indir, NULL, NULL,
389
14
                TSK_FS_ATTR_TYPE_UNIX_INDIR, TSK_FS_ATTR_ID_DEFAULT,
390
14
                fs_bufsize0 * (numSingIndirect + numDblIndirect +
391
14
                    numTripIndirect),
392
14
                fs_bufsize0 * (numSingIndirect + numDblIndirect +
393
14
                    numTripIndirect),
394
14
                fs_bufsize0 * (numSingIndirect + numDblIndirect +
395
14
                    numTripIndirect), 0, 0)) {
396
0
            return 1;
397
0
        }
398
399
14
        if ((buf[0] = (char *) tsk_malloc(fs_bufsize0)) == NULL) {
400
0
            return 1;
401
0
        }
402
403
14
        for (level = 1; length > 0 && level < 4; level++) {
404
14
            TSK_DADDR_T *addr_ptr = (TSK_DADDR_T *) fs_meta->content_ptr;
405
406
14
            if ((buf[level] = (char *) tsk_malloc(fs_bufsize1)) == NULL) {
407
0
                int f;
408
0
                for (f = 0; f < level; f++) {
409
0
                    free(buf[f]);
410
0
                }
411
0
                return 1;
412
0
            }
413
414
            /* the indirect addresses are stored in addr_ptr after the 12
415
             * direct addresses */
416
14
            read_b =
417
14
                unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir,
418
14
                buf, level, addr_ptr[12 + level - 1], length);
419
14
            if (read_b == -1)
420
14
                break;
421
0
            length -= read_b;
422
0
        }
423
424
        /*
425
         * Cleanup.
426
         */
427
70
        for (level = 0; level < 4; ++level) {
428
56
            free(buf[level]);
429
56
        }
430
14
    }
431
432
49
    if (read_b == -1) {
433
14
        fs_meta->attr_state = TSK_FS_META_ATTR_ERROR;
434
14
        if (fs_meta->flags & TSK_FS_META_FLAG_UNALLOC)
435
14
            tsk_error_set_errno(TSK_ERR_FS_RECOVER);
436
14
        return 1;
437
14
    }
438
439
35
    fs_meta->attr_state = TSK_FS_META_ATTR_STUDIED;
440
441
35
    return 0;
442
49
}
443
444
445
TSK_FS_ATTR_TYPE_ENUM
446
tsk_fs_unix_get_default_attr_type(const TSK_FS_FILE * a_file)
447
29.7k
{
448
29.7k
    return TSK_FS_ATTR_TYPE_DEFAULT;
449
29.7k
}
450
451
int
452
tsk_fs_unix_name_cmp(TSK_FS_INFO * a_fs_info, const char *s1,
453
    const char *s2)
454
0
{
455
0
    return strcmp(s1, s2);
456
0
}