Coverage Report

Created: 2025-09-27 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/fs/fs_open.c
Line
Count
Source
1
/*
2
** tsk_fs_open_img
3
** The Sleuth Kit
4
**
5
** Brian Carrier [carrier <at> sleuthkit [dot] org]
6
** Copyright (c) 2006-2011 Brian Carrier, Basis Technology.  All Rights reserved
7
** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
8
**
9
** TASK
10
** Copyright (c) 2002 Brian Carrier, @stake Inc.  All rights reserved
11
**
12
** Copyright (c) 1997,1998,1999, International Business Machines
13
** Corporation and others. All Rights Reserved.
14
*/
15
16
/* TCT */
17
/*++
18
 * LICENSE
19
 *  This software is distributed under the IBM Public License.
20
 * AUTHOR(S)
21
 *  Wietse Venema
22
 *  IBM T.J. Watson Research
23
 *  P.O. Box 704
24
 *  Yorktown Heights, NY 10598, USA
25
 --*/
26
27
#include "tsk_fs_i.h"
28
#include "tsk/util/detect_encryption.h"
29
#include "encryptionHelper.h"
30
#include "tsk/img/unsupported_types.h"
31
32
/**
33
 * \file fs_open.c
34
 * Contains the general code to open a file system -- this calls
35
 * the file system -specific opening routines.
36
 */
37
38
39
/**
40
 * \ingroup fslib
41
 * Tries to process data in a volume as a file system.
42
 * Returns a structure that can be used for analysis and reporting.
43
 *
44
 * @param a_part_info Open volume to read from and analyze
45
 * @param a_ftype Type of file system (or autodetect)
46
 *
47
 * @return NULL on error
48
 */
49
TSK_FS_INFO *
50
tsk_fs_open_vol(const TSK_VS_PART_INFO * a_part_info,
51
    TSK_FS_TYPE_ENUM a_ftype)
52
0
{
53
0
    return tsk_fs_open_vol_decrypt(a_part_info, a_ftype, "");
54
0
}
55
56
/**
57
 * \ingroup fslib
58
 * Tries to process data in a volume as a file system.
59
 * Allows for providing an optional password for decryption.
60
 * Returns a structure that can be used for analysis and reporting.
61
 *
62
 * @param a_part_info Open volume to read from and analyze
63
 * @param a_ftype Type of file system (or autodetect)
64
 * @param a_pass Password to decrypt filesystem
65
 *
66
 * @return NULL on error
67
 */
68
TSK_FS_INFO *
69
tsk_fs_open_vol_decrypt(const TSK_VS_PART_INFO * a_part_info,
70
    TSK_FS_TYPE_ENUM a_ftype, const char * a_pass)
71
0
{
72
0
    TSK_OFF_T offset;
73
0
    if (a_part_info == NULL) {
74
0
        tsk_error_reset();
75
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
76
0
        tsk_error_set_errstr("tsk_fs_open_vol: Null vpart handle");
77
0
        return NULL;
78
0
    }
79
0
    else if ((a_part_info->vs == NULL)
80
0
        || (a_part_info->vs->tag != TSK_VS_INFO_TAG)) {
81
0
        tsk_error_reset();
82
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
83
0
        tsk_error_set_errstr("tsk_fs_open_vol: Null vs handle");
84
0
        return NULL;
85
0
    }
86
87
0
    offset =
88
0
        a_part_info->start * a_part_info->vs->block_size +
89
0
        a_part_info->vs->offset;
90
0
    return tsk_fs_open_img_decrypt(a_part_info->vs->img_info, offset,
91
0
        a_ftype, a_pass);
92
0
}
93
94
/**
95
 * \ingroup fslib
96
 * Tries to process data in a disk image at a given offset as a file system.
97
 * Returns a structure that can be used for analysis and reporting.
98
 *
99
 * @param a_img_info Disk image to analyze
100
 * @param a_offset Byte offset to start analyzing from
101
 * @param a_ftype Type of file system (or autodetect)
102
 *
103
 * @return NULL on error
104
 */
105
TSK_FS_INFO *
106
tsk_fs_open_img(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset,
107
    TSK_FS_TYPE_ENUM a_ftype)
108
11.5k
{
109
11.5k
    return tsk_fs_open_img_decrypt(a_img_info, a_offset, a_ftype, "");
110
11.5k
}
111
112
/**
113
 * \ingroup fslib
114
 * Tries to process data in a disk image at a given offset as a file system.
115
 * Allows for providing an optional password for decryption.
116
 * Returns a structure that can be used for analysis and reporting.
117
 *
118
 * @param a_img_info Disk image to analyze
119
 * @param a_offset Byte offset to start analyzing from
120
 * @param a_ftype Type of file system (or autodetect)
121
 * @param a_pass Password to decrypt filesystem. Currently only used if type is specified.
122
 *
123
 * @return NULL on error
124
 */
125
TSK_FS_INFO *
126
tsk_fs_open_img_decrypt(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset,
127
    TSK_FS_TYPE_ENUM a_ftype, const char * a_pass)
128
11.5k
{
129
11.5k
    TSK_FS_INFO *fs_info;
130
11.5k
    const struct {
131
11.5k
        char* name;
132
11.5k
        TSK_FS_INFO* (*open)(TSK_IMG_INFO*, TSK_OFF_T,
133
11.5k
                                 TSK_FS_TYPE_ENUM, const char*, uint8_t);
134
        // This type should be the _DETECT version because it used
135
        // during autodetection
136
11.5k
        TSK_FS_TYPE_ENUM type;
137
11.5k
    } FS_OPENERS[] = {
138
11.5k
        { "NTFS",     ntfs_open,    TSK_FS_TYPE_NTFS_DETECT    },
139
11.5k
        { "FAT",      fatfs_open,   TSK_FS_TYPE_FAT_DETECT     },
140
11.5k
        { "EXT2/3/4", ext2fs_open,  TSK_FS_TYPE_EXT_DETECT     },
141
11.5k
        { "UFS",      ffs_open,     TSK_FS_TYPE_FFS_DETECT     },
142
11.5k
        { "YAFFS2",   yaffs2_open,  TSK_FS_TYPE_YAFFS2_DETECT  },
143
11.5k
        { "XFS",      xfs_open,     TSK_FS_TYPE_XFS_DETECT     },
144
11.5k
#if TSK_USE_HFS
145
11.5k
        { "HFS",      hfs_open,     TSK_FS_TYPE_HFS_DETECT     },
146
11.5k
#endif
147
11.5k
        { "ISO9660",  iso9660_open, TSK_FS_TYPE_ISO9660_DETECT },
148
11.5k
        { "APFS",     apfs_open_auto_detect,    TSK_FS_TYPE_APFS_DETECT },
149
11.5k
        { "BTRFS",    btrfs_open,   TSK_FS_TYPE_BTRFS_DETECT },
150
11.5k
    };
151
11.5k
    if (a_img_info == NULL) {
152
0
        tsk_error_reset();
153
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
154
0
        tsk_error_set_errstr("tsk_fs_open_img: Null image handle");
155
0
        return NULL;
156
0
    }
157
158
  /* If the image is type IMG_DIR_INFO, then the file system is
159
   * automatically the logical directory file system type. It is an
160
   * error to try to use any other file system type in that case.
161
   */
162
11.5k
  if (a_img_info->itype == TSK_IMG_TYPE_LOGICAL) {
163
0
    if (!(a_ftype == TSK_FS_TYPE_DETECT || a_ftype == TSK_FS_TYPE_LOGICAL)) {
164
0
      tsk_error_reset();
165
0
      tsk_error_set_errno(TSK_ERR_FS_ARG);
166
0
      tsk_error_set_errstr("tsk_fs_open_img: Incompatible file system type given for logical file image");
167
0
      return NULL;
168
0
    }
169
170
0
    return logical_fs_open(a_img_info);
171
0
  }
172
173
    /* We will try different file systems ...
174
     * We need to try all of them in case more than one matches
175
     */
176
11.5k
    if (a_ftype == TSK_FS_TYPE_DETECT) {
177
0
        unsigned long i;
178
0
        const char *name_first = "";
179
0
        TSK_FS_INFO *fs_first = NULL;
180
181
0
        if (tsk_verbose)
182
0
            tsk_fprintf(stderr,
183
0
                "fsopen: Auto detection mode at offset %" PRIdOFF "\n",
184
0
                a_offset);
185
186
0
        int haveErrorToPreserve = 0;
187
0
        uint32_t errorCodeToPreserve;
188
0
        char errorStrToPreserve[TSK_ERROR_STRING_MAX_LENGTH + 1];
189
190
0
        for (i = 0; i < sizeof(FS_OPENERS)/sizeof(FS_OPENERS[0]); ++i) {
191
0
            if ((fs_info = FS_OPENERS[i].open(
192
0
                    a_img_info, a_offset, FS_OPENERS[i].type, a_pass, 1)) != NULL) {
193
                // fs opens as type i
194
0
                if (fs_first == NULL) {
195
                    // first success opening fs
196
0
                    name_first = FS_OPENERS[i].name;
197
0
                    fs_first = fs_info;
198
0
                }
199
0
                else {
200
                    // second success opening fs, which means we
201
                    // cannot autodetect the fs type and must give up
202
0
                    fs_first->close(fs_first);
203
0
                    fs_info->close(fs_info);
204
0
                    tsk_error_reset();
205
0
                    tsk_error_set_errno(TSK_ERR_FS_MULTTYPE);
206
0
                    tsk_error_set_errstr(
207
0
                        "%s or %s", FS_OPENERS[i].name, name_first);
208
0
                    return NULL;
209
0
                }
210
0
            }
211
0
            else {
212
                // fs does not open as type i
213
214
                // TSK_ERR_FS_BITLOCKER_ERROR is used when we get pretty far into the BitLocker processing but
215
                // need something different from the user or find something we can't currently parse. We need
216
                // to keep trying file systems (we might have a FAT system so we don't want to return after
217
                // failing to open as NTFS) but we also want to be able to get the error back to the user.
218
0
                if (tsk_error_get_errno() == TSK_ERR_FS_BITLOCKER_ERROR) {
219
0
                    haveErrorToPreserve = 1;
220
0
                    errorCodeToPreserve = tsk_error_get_errno();
221
0
                    memset(errorStrToPreserve, 0, TSK_ERROR_STRING_MAX_LENGTH + 1);
222
0
                    strncpy(errorStrToPreserve, tsk_error_get_errstr(), TSK_ERROR_STRING_MAX_LENGTH);
223
0
                }
224
225
0
                tsk_error_reset();
226
0
            }
227
0
        }
228
229
        // If we have an error to report, set it now and return
230
0
        if (haveErrorToPreserve) {
231
0
            tsk_error_reset();
232
0
            tsk_error_set_errno(errorCodeToPreserve);
233
0
            tsk_error_set_errstr("%s", errorStrToPreserve);
234
0
            return NULL;
235
0
        }
236
237
0
        if (fs_first == NULL) {
238
0
            tsk_error_reset();
239
240
            // If we're still at the start of the image and haven't identified any volume systems or file
241
            // systems, check if the image type is a known unsupported type.
242
0
            int unsupportedSignatureFound = 0;
243
0
            if (a_offset == 0) {
244
0
                char * imageType = detectUnsupportedImageType(a_img_info);
245
0
                if (imageType != NULL) {
246
0
                    unsupportedSignatureFound = 1;
247
0
                    tsk_error_reset();
248
0
                    tsk_error_set_errno(TSK_ERR_IMG_UNSUPTYPE);
249
0
                    tsk_error_set_errstr("%s", imageType);
250
0
                    free(imageType);
251
0
                }
252
0
            }
253
254
0
            if (!unsupportedSignatureFound) {
255
                // Check if the file system appears to be encrypted
256
0
                encryption_detected_result* result = detectVolumeEncryption(a_img_info, a_offset);
257
0
                if (result != NULL) {
258
0
                    if (result->encryptionType == ENCRYPTION_DETECTED_SIGNATURE) {
259
0
                        tsk_error_set_errno(TSK_ERR_FS_ENCRYPTED);
260
0
                        tsk_error_set_errstr("%s", result->desc);
261
0
                    }
262
0
                    else if (result->encryptionType == ENCRYPTION_DETECTED_ENTROPY) {
263
0
                        tsk_error_set_errno(TSK_ERR_FS_POSSIBLY_ENCRYPTED);
264
0
                        tsk_error_set_errstr("%s", result->desc);
265
0
                    }
266
0
                    else {
267
0
                        tsk_error_set_errno(TSK_ERR_FS_UNKTYPE);
268
0
                    }
269
0
                    free(result);
270
0
                    result = NULL;
271
0
                }
272
0
                else {
273
0
                    tsk_error_set_errno(TSK_ERR_FS_UNKTYPE);
274
0
                }
275
0
            }
276
0
        }
277
0
        return fs_first;
278
0
    }
279
11.5k
    else if (TSK_FS_TYPE_ISNTFS(a_ftype)) {
280
2.82k
        return ntfs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
281
2.82k
    }
282
8.72k
    else if (TSK_FS_TYPE_ISFAT(a_ftype)) {
283
39
        return fatfs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
284
39
    }
285
8.68k
    else if (TSK_FS_TYPE_ISFFS(a_ftype)) {
286
0
        return ffs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
287
0
    }
288
8.68k
    else if (TSK_FS_TYPE_ISEXT(a_ftype)) {
289
3.47k
        return ext2fs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
290
3.47k
    }
291
5.21k
    else if (TSK_FS_TYPE_ISHFS(a_ftype)) {
292
3.37k
        return hfs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
293
3.37k
    }
294
1.83k
    else if (TSK_FS_TYPE_ISISO9660(a_ftype)) {
295
1.52k
        return iso9660_open(a_img_info, a_offset, a_ftype, a_pass, 0);
296
1.52k
    }
297
304
    else if (TSK_FS_TYPE_ISRAW(a_ftype)) {
298
0
        return rawfs_open(a_img_info, a_offset);
299
0
    }
300
304
    else if (TSK_FS_TYPE_ISSWAP(a_ftype)) {
301
0
        return swapfs_open(a_img_info, a_offset);
302
0
    }
303
304
    else if (TSK_FS_TYPE_ISYAFFS2(a_ftype)) {
304
0
        return yaffs2_open(a_img_info, a_offset, a_ftype, a_pass, 0);
305
0
    }
306
304
    else if (TSK_FS_TYPE_ISBTRFS(a_ftype)) {
307
302
        return btrfs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
308
302
    }
309
2
    else if (TSK_FS_TYPE_ISAPFS(a_ftype)) {
310
2
        return apfs_open(a_img_info, a_offset, a_ftype, a_pass);
311
2
    }
312
0
    else if (TSK_FS_TYPE_ISXFS(a_ftype)) {
313
0
        return xfs_open(a_img_info, a_offset, a_ftype, a_pass, 0);
314
0
    }
315
0
    tsk_error_reset();
316
0
    tsk_error_set_errno(TSK_ERR_FS_UNSUPTYPE);
317
0
    tsk_error_set_errstr("%X", (int) a_ftype);
318
0
    return NULL;
319
11.5k
}
320
321
/**
322
 * \ingroup fslib
323
 * Close an open file system.
324
 * @param a_fs File system to close.
325
 */
326
void
327
tsk_fs_close(TSK_FS_INFO * a_fs)
328
9.32k
{
329
9.32k
    if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG))
330
0
        return;
331
332
    // each file system is supposed to call tsk_fs_free()
333
334
9.32k
    a_fs->close(a_fs);
335
9.32k
}
336
337
/* tsk_fs_malloc - init lock after tsk_malloc
338
 * This is for fs module and all it's inheritances
339
 */
340
TSK_FS_INFO *
341
tsk_fs_malloc(size_t a_len)
342
32.3k
{
343
32.3k
    TSK_FS_INFO *fs_info;
344
32.3k
    if ((fs_info = (TSK_FS_INFO *) tsk_malloc(a_len)) == NULL)
345
0
        return NULL;
346
32.3k
    tsk_init_lock(&fs_info->list_inum_named_lock);
347
32.3k
    tsk_init_lock(&fs_info->orphan_dir_lock);
348
349
32.3k
    fs_info->list_inum_named = NULL;
350
351
32.3k
    return fs_info;
352
32.3k
}
353
354
/* tsk_fs_free - deinit lock before free memory
355
 * This is for fs module and all it's inheritances
356
 */
357
void
358
tsk_fs_free(TSK_FS_INFO * a_fs_info)
359
32.3k
{
360
32.3k
    if (a_fs_info->list_inum_named) {
361
1.19k
        tsk_list_free(a_fs_info->list_inum_named);
362
1.19k
        a_fs_info->list_inum_named = NULL;
363
1.19k
    }
364
365
    /* Free any encryption structures */
366
32.3k
    freeEncryptionData(a_fs_info);
367
368
    /* we should probably get the lock, but we're
369
     * about to kill the entire object so there are
370
     * bigger problems if another thread is still
371
     * using the fs */
372
32.3k
    if (a_fs_info->orphan_dir) {
373
1.65k
        tsk_fs_dir_close(a_fs_info->orphan_dir);
374
1.65k
        a_fs_info->orphan_dir = NULL;
375
1.65k
    }
376
377
378
32.3k
    tsk_deinit_lock(&a_fs_info->list_inum_named_lock);
379
32.3k
    tsk_deinit_lock(&a_fs_info->orphan_dir_lock);
380
381
32.3k
    free(a_fs_info);
382
32.3k
}