Coverage Report

Created: 2025-08-29 06:55

/src/sleuthkit/tsk/vs/mm_open.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) 2003-2011 Brian Carrier.  All rights reserved
6
 *
7
 * tsk_vs_open - wrapper function for specific partition type
8
 *
9
 * This software is distributed under the Common Public License 1.0
10
 */
11
12
/**
13
 * \file mm_open.c
14
 * Contains general code to open volume systems.
15
 */
16
17
#include "tsk_vs_i.h"
18
#include "tsk/util/detect_encryption.h"
19
20
21
/**
22
 * \ingroup vslib
23
 *
24
 * Open a disk image and process the media management system
25
 * data.  This calls VS specific code to determine the type and
26
 * collect data.
27
 *
28
 * @param img_info The opened disk image.
29
 * @param offset Byte offset in the disk image to start analyzing from.
30
 * @param type Type of volume system (including auto detect)
31
 *
32
 * @return NULL on error.
33
 */
34
TSK_VS_INFO *
35
tsk_vs_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset,
36
    TSK_VS_TYPE_ENUM type)
37
13.2k
{
38
13.2k
    if (img_info == NULL) {
39
        /* Opening the image file(s) failed, if attempted. */
40
0
        tsk_error_reset();
41
0
        tsk_error_set_errno(TSK_ERR_IMG_NOFILE);
42
0
        tsk_error_set_errstr("mm_open");
43
0
        return NULL;
44
0
    }
45
46
13.2k
  if (img_info->itype == TSK_IMG_TYPE_LOGICAL) {
47
0
    tsk_error_reset();
48
0
    tsk_error_set_errno(TSK_ERR_VS_UNSUPTYPE);
49
0
    tsk_error_set_errstr("Logical image type can not have a volume system");
50
0
    return NULL;
51
0
  }
52
53
    /* Autodetect mode
54
     * We need to try all of them in case there are multiple
55
     * installations
56
     *
57
     * NOte that errors that are encountered during the testing process
58
     * will not be reported
59
     */
60
13.2k
    if (type == TSK_VS_TYPE_DETECT) {
61
0
        TSK_VS_INFO *vs, *prev_vs = NULL;
62
0
        char *prev_type = NULL;
63
64
0
        if ((vs = tsk_vs_dos_open(img_info, offset, 1)) != NULL) {
65
0
            prev_type = "DOS";
66
0
            prev_vs = vs;
67
0
        }
68
0
        else {
69
0
            tsk_error_reset();
70
0
        }
71
72
0
        if ((vs = tsk_vs_bsd_open(img_info, offset)) != NULL) {
73
            // if (prev_type == NULL) {
74
            // In this case, BSD takes priority because BSD partitions start off with
75
            // the DOS magic value in the first sector with the boot code.
76
0
            prev_type = "BSD";
77
0
            prev_vs = vs;
78
            /*
79
               }
80
               else {
81
               prev_vs->close(prev_vs);
82
               vs->close(vs);
83
               tsk_error_reset();
84
               tsk_error_set_errno(TSK_ERR_VS_UNKTYPE);
85
               tsk_error_set_errstr(
86
               "BSD or %s at %" PRIuDADDR, prev_type, offset);
87
               tsk_errstr2[0] = '\0';
88
               return NULL;
89
               }
90
             */
91
0
        }
92
0
        else {
93
0
            tsk_error_reset();
94
0
        }
95
96
0
        if ((vs = tsk_vs_gpt_open(img_info, offset)) != NULL) {
97
98
0
            if ((prev_type != NULL) && (strcmp(prev_type, "DOS") == 0) && (vs->is_backup)) {
99
                /* In this case we've found a DOS partition and a backup GPT partition.
100
                 * The DOS partition takes priority in this case (and are already in prev_type and prev_vs) */
101
0
                vs->close(vs);
102
0
                if (tsk_verbose)
103
0
                    tsk_fprintf(stderr,
104
0
                        "mm_open: Ignoring secondary GPT Partition\n");
105
0
            }
106
0
            else {
107
0
                if (prev_type != NULL) {
108
109
                    /* GPT drives have a DOS Safety partition table.
110
                     * Test to see if the GPT has a safety partiiton
111
                     * and then we can igore the DOS */
112
0
                    if (strcmp(prev_type, "DOS") == 0) {
113
0
                        TSK_VS_PART_INFO *tmp_set;
114
0
                        for (tmp_set = prev_vs->part_list; tmp_set;
115
0
                            tmp_set = tmp_set->next) {
116
0
                            if ((tmp_set->desc)
117
0
                                && (strncmp(tmp_set->desc, "GPT Safety",
118
0
                                    10) == 0)
119
0
                                && (tmp_set->start <= 63)) {
120
121
0
                                if (tsk_verbose)
122
0
                                    tsk_fprintf(stderr,
123
0
                                        "mm_open: Ignoring DOS Safety GPT Partition\n");
124
0
                                prev_type = NULL;
125
0
                                prev_vs->close(prev_vs);
126
0
                                prev_vs = NULL;
127
0
                                break;
128
0
                            }
129
0
                        }
130
0
                    }
131
132
                    /* If we never found the safety, then we have a conflict. */
133
0
                    if (prev_type != NULL) {
134
0
                        prev_vs->close(prev_vs);
135
0
                        vs->close(vs);
136
0
                        tsk_error_reset();
137
0
                        tsk_error_set_errno(TSK_ERR_VS_MULTTYPE);
138
0
                        tsk_error_set_errstr("GPT or %s at %" PRIuDADDR, prev_type,
139
0
                            offset);
140
0
                        return NULL;
141
0
                    }
142
0
                }
143
0
                prev_type = "GPT";
144
0
                prev_vs = vs;
145
0
            }
146
0
        }
147
0
        else {
148
0
            tsk_error_reset();
149
0
        }
150
151
0
        if ((vs = tsk_vs_sun_open(img_info, offset)) != NULL) {
152
0
            if (prev_type == NULL) {
153
0
                prev_type = "Sun";
154
0
                prev_vs = vs;
155
0
            }
156
0
            else {
157
0
                prev_vs->close(prev_vs);
158
0
                vs->close(vs);
159
0
                tsk_error_reset();
160
0
                tsk_error_set_errno(TSK_ERR_VS_MULTTYPE);
161
0
                tsk_error_set_errstr("Sun or %s at %" PRIuDADDR, prev_type,
162
0
                    offset);
163
0
                return NULL;
164
0
            }
165
0
        }
166
0
        else {
167
0
            tsk_error_reset();
168
0
        }
169
170
0
        if ((vs = tsk_vs_mac_open(img_info, offset)) != NULL) {
171
0
            if (prev_type == NULL) {
172
0
                prev_type = "Mac";
173
0
                prev_vs = vs;
174
0
            }
175
0
            else {
176
0
                prev_vs->close(prev_vs);
177
0
                vs->close(vs);
178
0
                tsk_error_reset();
179
0
                tsk_error_set_errno(TSK_ERR_VS_MULTTYPE);
180
0
                tsk_error_set_errstr("Mac or %s at %" PRIuDADDR, prev_type,
181
0
                    offset);
182
0
                return NULL;
183
0
            }
184
0
        }
185
0
        else {
186
0
            tsk_error_reset();
187
0
        }
188
189
0
        if (prev_vs == NULL) {
190
0
            tsk_error_reset();
191
192
            // Check whether the volume system appears to be encrypted.
193
            // Note that detectDiskEncryption does not do an entropy calculation - high entropy
194
            // files will be reported by tsk_fs_open_img().
195
0
            encryption_detected_result* result = detectDiskEncryption(img_info, offset);
196
0
            if (result != NULL) {
197
0
                if (result->encryptionType == ENCRYPTION_DETECTED_SIGNATURE) {
198
0
                    tsk_error_set_errno(TSK_ERR_VS_ENCRYPTED);
199
0
                    tsk_error_set_errstr("%s", result->desc);
200
0
                }
201
0
                free(result);
202
0
                result = NULL;
203
0
            }
204
0
            else {
205
0
                tsk_error_set_errno(TSK_ERR_VS_UNKTYPE);
206
0
            }
207
0
            return NULL;
208
0
        }
209
210
0
        return prev_vs;
211
0
    }
212
213
    // Not autodetect
214
13.2k
    else {
215
216
13.2k
        switch (type) {
217
1.27k
        case TSK_VS_TYPE_DOS:
218
1.27k
            return tsk_vs_dos_open(img_info, offset, 0);
219
591
        case TSK_VS_TYPE_MAC:
220
591
            return tsk_vs_mac_open(img_info, offset);
221
0
        case TSK_VS_TYPE_BSD:
222
0
            return tsk_vs_bsd_open(img_info, offset);
223
596
        case TSK_VS_TYPE_SUN:
224
596
            return tsk_vs_sun_open(img_info, offset);
225
10.7k
        case TSK_VS_TYPE_GPT:
226
10.7k
            return tsk_vs_gpt_open(img_info, offset);
227
0
        case TSK_VS_TYPE_APFS: // Not supported yet
228
0
        case TSK_VS_TYPE_LVM: // Not supported yet
229
0
        case TSK_VS_TYPE_UNSUPP:
230
0
        default:
231
0
            tsk_error_reset();
232
0
            tsk_error_set_errno(TSK_ERR_VS_UNSUPTYPE);
233
0
            tsk_error_set_errstr("%d", type);
234
0
            return NULL;
235
13.2k
        }
236
13.2k
    }
237
13.2k
}
238
239
/**
240
 * \ingroup vslib
241
 * Closes an open volume system
242
 * @param a_vs Pointer to the open volume system structure.
243
 */
244
void
245
tsk_vs_close(TSK_VS_INFO * a_vs)
246
2.77k
{
247
2.77k
    if (a_vs == NULL) {
248
0
        return;
249
0
    }
250
2.77k
    a_vs->close((TSK_VS_INFO *) a_vs);
251
2.77k
}