Coverage Report

Created: 2025-09-27 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/vs/sun.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
 * SUN - Sun VTOC code
9
 *
10
 * This software is distributed under the Common Public License 1.0
11
 */
12
13
/** \file sun.c
14
 * Contains the internal SUN VTOC volume system processing code.
15
 */
16
#include "tsk_vs_i.h"
17
#include "tsk_sun.h"
18
19
20
/*
21
 * Return a buffer with a description of the partition type
22
 */
23
static char *
24
sun_get_desc(uint16_t fstype)
25
2.24k
{
26
2.24k
    char *str = tsk_malloc(64);
27
2.24k
    if (str == NULL)
28
0
        return "";
29
2.24k
    switch (fstype) {
30
31
310
    case 0:
32
310
        strncpy(str, "Unassigned (0x00)", 64);
33
310
        break;
34
97
    case 1:
35
97
        strncpy(str, "boot (0x01)", 64);
36
97
        break;
37
67
    case 2:
38
67
        strncpy(str, "/ (0x02)", 64);
39
67
        break;
40
73
    case 3:
41
73
        strncpy(str, "swap (0x03)", 64);
42
73
        break;
43
125
    case 4:
44
125
        strncpy(str, "/usr/ (0x04)", 64);
45
125
        break;
46
417
    case 5:
47
417
        strncpy(str, "backup (0x05)", 64);
48
417
        break;
49
71
    case 6:
50
71
        strncpy(str, "stand (0x06)", 64);
51
71
        break;
52
93
    case 7:
53
93
        strncpy(str, "/var/ (0x07)", 64);
54
93
        break;
55
89
    case 8:
56
89
        strncpy(str, "/home/ (0x08)", 64);
57
89
        break;
58
63
    case 9:
59
63
        strncpy(str, "alt sector (0x09)", 64);
60
63
        break;
61
96
    case 10:
62
96
        strncpy(str, "cachefs (0x0A)", 64);
63
96
        break;
64
747
    default:
65
747
        snprintf(str, 64, "Unknown Type (0x%.4x)", fstype);
66
747
        break;
67
2.24k
    }
68
69
2.24k
    return str;
70
2.24k
}
71
72
73
/*
74
 * Load an Intel disk label, this is called by sun_load_table
75
 */
76
77
static uint8_t
78
sun_load_table_i386(TSK_VS_INFO * vs, sun_dlabel_i386 * dlabel_x86)
79
178
{
80
178
    uint32_t idx = 0;
81
178
    uint16_t num_parts;
82
178
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector
83
84
178
    if (tsk_verbose)
85
0
        tsk_fprintf(stderr, "load_table_i386: Number of partitions: %d\n",
86
0
            tsk_getu16(vs->endian, dlabel_x86->num_parts));
87
88
178
    num_parts = tsk_getu16(vs->endian, dlabel_x86->num_parts);
89
178
    if (num_parts > 16) {
90
153
        num_parts = 16;
91
153
    }
92
93
    /* Cycle through the partitions, there are 16 for i386 */
94
1.99k
    for (idx = 0; idx < num_parts; idx++) {
95
1.87k
        TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
96
97
1.87k
        if (tsk_verbose)
98
0
            tsk_fprintf(stderr,
99
0
                "load_table_i386: %" PRIu32
100
0
                "  Starting Sector: %" PRIu32 "  Size: %" PRIu32
101
0
                "  Type: %" PRIu16 "\n", idx, tsk_getu32(vs->endian,
102
0
                    dlabel_x86->part[idx].start_sec),
103
0
                tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec),
104
0
                tsk_getu16(vs->endian, dlabel_x86->part[idx].type));
105
106
1.87k
        if (tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec) == 0)
107
334
            continue;
108
109
        // make sure the first couple are in the image bounds
110
1.54k
        if ((idx < 2) && (tsk_getu32(vs->endian,
111
213
                    dlabel_x86->part[idx].start_sec) > max_addr)) {
112
56
            tsk_error_reset();
113
56
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
114
56
            tsk_error_set_errstr
115
56
                ("sun_load_i386: Starting sector too large for image");
116
56
            return 1;
117
56
        }
118
119
        // set the entry that covers the entire disk image as DESC
120
1.48k
        if ((tsk_getu16(vs->endian, dlabel_x86->part[idx].type) == 5)
121
224
            && (tsk_getu32(vs->endian,
122
224
                    dlabel_x86->part[idx].start_sec) == 0))
123
68
            ptype = TSK_VS_PART_FLAG_META;
124
125
        /* Add the partition to the internal sorted list */
126
1.48k
        if (NULL == tsk_vs_part_add(vs,
127
1.48k
                (TSK_DADDR_T) tsk_getu32(vs->endian,
128
1.48k
                    dlabel_x86->part[idx].start_sec),
129
1.48k
                (TSK_DADDR_T) tsk_getu32(vs->endian,
130
1.48k
                    dlabel_x86->part[idx].size_sec), ptype,
131
1.48k
                sun_get_desc(tsk_getu16(vs->endian,
132
1.48k
                        dlabel_x86->part[idx].type)), -1, idx)) {
133
0
            return 1;
134
0
        }
135
1.48k
    }
136
137
122
    return 0;
138
178
}
139
140
141
/* load a sparc disk label, this is called from the general
142
 * sun_load_table
143
 */
144
static uint8_t
145
sun_load_table_sparc(TSK_VS_INFO * vs, sun_dlabel_sparc * dlabel_sp)
146
153
{
147
153
    uint32_t idx = 0;
148
153
    uint32_t cyl_conv;
149
153
    uint16_t num_parts;
150
153
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector
151
152
    /* The value to convert cylinders to sectors */
153
153
    cyl_conv = (uint32_t) tsk_getu16(vs->endian, dlabel_sp->sec_per_tr) *
154
153
        tsk_getu16(vs->endian, dlabel_sp->num_head);
155
156
153
    if (tsk_verbose)
157
0
        tsk_fprintf(stderr, "load_table_sparc: Number of partitions: %d\n",
158
0
            tsk_getu16(vs->endian, dlabel_sp->num_parts));
159
160
153
    num_parts = tsk_getu16(vs->endian, dlabel_sp->num_parts);
161
153
    if (num_parts > 8) {
162
129
        num_parts = 8;
163
129
    }
164
165
    /* Cycle through the partitions, there are 8 for sparc */
166
1.06k
    for (idx = 0; idx < num_parts; idx++) {
167
944
        TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
168
944
        uint32_t part_start = cyl_conv * tsk_getu32(vs->endian,
169
944
            dlabel_sp->part_layout[idx].start_cyl);
170
171
944
        uint32_t part_size = tsk_getu32(vs->endian,
172
944
            dlabel_sp->part_layout[idx].size_blk);
173
174
944
        if (tsk_verbose)
175
0
            tsk_fprintf(stderr,
176
0
                "load_table_sparc: %" PRIu32
177
0
                "  Starting Sector: %" PRIu32 "  Size: %" PRIu32
178
0
                "  Type: %" PRIu16 "\n", idx, part_start, part_size,
179
0
                tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type));
180
181
944
        if (part_size == 0)
182
148
            continue;
183
184
        // make sure the first couple are in the image bounds
185
796
        if ((idx < 2) && (part_start > max_addr)) {
186
33
            tsk_error_reset();
187
33
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
188
33
            tsk_error_set_errstr
189
33
                ("sun_load_sparc: Starting sector too large for image");
190
33
            return 1;
191
33
        }
192
193
        // set the entry that covers the entire disk image as DESC
194
763
        if ((tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type) == 5)
195
193
            && (part_start == 0))
196
72
            ptype = TSK_VS_PART_FLAG_META;
197
198
        /* Add the partition to the internal sorted list */
199
763
        if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
200
763
                (TSK_DADDR_T) part_size, ptype,
201
763
                sun_get_desc(tsk_getu16(vs->endian,
202
763
                        dlabel_sp->part_meta[idx].type)), -1, idx))
203
0
            return 1;
204
205
763
    }
206
207
120
    return 0;
208
153
}
209
210
211
/*
212
 * Process the partition table at the sector address
213
 *
214
 * This method just finds out if it is sparc or Intel and then
215
 * calls the appropriate method
216
 *
217
 * Return 0 on success and 1 on error
218
 */
219
static uint8_t
220
sun_load_table(TSK_VS_INFO * vs)
221
584
{
222
584
    sun_dlabel_sparc *dlabel_sp;
223
584
    sun_dlabel_i386 *dlabel_x86;
224
584
    char *buf;
225
584
    ssize_t cnt;
226
584
    TSK_DADDR_T taddr =
227
584
        vs->offset / vs->block_size + SUN_SPARC_PART_SOFFSET;
228
584
    int result = 0;
229
230
231
    /* Sanity check in case label sizes change */
232
584
    if ((sizeof(*dlabel_sp) > vs->block_size) ||
233
584
        (sizeof(*dlabel_x86) > vs->block_size)) {
234
0
        tsk_error_reset();
235
0
        tsk_error_set_errno(TSK_ERR_VS_BUF);
236
0
        tsk_error_set_errstr
237
0
            ("sun_load_table: disk labels bigger than block size");
238
0
        return 1;
239
0
    }
240
241
584
    if (tsk_verbose)
242
0
        tsk_fprintf(stderr,
243
0
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr);
244
245
584
    if ((buf = tsk_malloc(vs->block_size)) == NULL) {
246
0
        goto on_error;
247
0
    }
248
249
    /* Try the given offset */
250
584
    cnt = tsk_vs_read_block
251
584
        (vs, SUN_SPARC_PART_SOFFSET, buf, vs->block_size);
252
253
    /* If -1 is returned, tsk_errno is already set */
254
584
    if (cnt != vs->block_size) {
255
17
        if (cnt >= 0) {
256
17
            tsk_error_reset();
257
17
            tsk_error_set_errno(TSK_ERR_VS_READ);
258
17
        }
259
17
        tsk_error_set_errstr2("SUN Disk Label in Sector: %" PRIuDADDR,
260
17
            taddr);
261
17
        goto on_error;
262
17
    }
263
264
265
    /* Check the magic value
266
     * Both intel and sparc have the magic value in the same location
267
     *
268
     * We try both in case someone specifies the exact location of the
269
     * intel disk label.
270
     * */
271
567
    dlabel_sp = (sun_dlabel_sparc *) buf;
272
567
    dlabel_x86 = (sun_dlabel_i386 *) buf;
273
567
    if (tsk_vs_guessu16(vs, dlabel_sp->magic, SUN_MAGIC) == 0) {
274
406
        if (tsk_getu32(vs->endian, dlabel_sp->sanity) == SUN_SANITY) {
275
153
            result = sun_load_table_sparc(vs, dlabel_sp);
276
            // TODO: I assume based on the existing free that the previous function
277
            // does not take ownership of buf.
278
153
            free(buf);
279
153
            return result;
280
153
        }
281
253
        else if (tsk_getu32(vs->endian, dlabel_x86->sanity) == SUN_SANITY) {
282
176
            result = sun_load_table_i386(vs, dlabel_x86);
283
            // TODO: I assume based on the existing free that the previous function
284
            // does not take ownership of buf.
285
176
            free(buf);
286
176
            return result;
287
176
        }
288
406
    }
289
290
291
    /* Now try the next sector, which is where the intel
292
     * could be stored */
293
294
238
    taddr = vs->offset / vs->block_size / SUN_I386_PART_SOFFSET;
295
238
    if (tsk_verbose)
296
0
        tsk_fprintf(stderr,
297
0
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr + 1);
298
299
238
    cnt = tsk_vs_read_block
300
238
        (vs, SUN_I386_PART_SOFFSET, buf, vs->block_size);
301
302
238
    if (cnt != vs->block_size) {
303
110
        if (cnt >= 0) {
304
16
            tsk_error_reset();
305
16
            tsk_error_set_errno(TSK_ERR_VS_READ);
306
16
        }
307
110
        tsk_error_set_errstr2("SUN (Intel) Disk Label in Sector: %"
308
110
            PRIuDADDR, taddr);
309
110
        goto on_error;
310
110
    }
311
312
128
    dlabel_x86 = (sun_dlabel_i386 *) buf;
313
128
    if (tsk_vs_guessu16(vs, dlabel_x86->magic, SUN_MAGIC)) {
314
66
        tsk_error_reset();
315
66
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
316
66
        tsk_error_set_errstr("SUN (intel) partition table (Sector: %"
317
66
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
318
66
                dlabel_sp->magic));
319
66
        goto on_error;
320
66
    }
321
322
62
    if (tsk_getu32(vs->endian, dlabel_x86->sanity) != SUN_SANITY) {
323
60
        tsk_error_reset();
324
60
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
325
60
        tsk_error_set_errstr("SUN (intel) sanity value (Sector: %"
326
60
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
327
60
                dlabel_sp->magic));
328
60
        goto on_error;
329
60
    }
330
331
2
    result = sun_load_table_i386(vs, dlabel_x86);
332
    // TODO: I assume based on the existing free that the previous function
333
    // does not take ownership of buf.
334
2
    free(buf);
335
2
    return result;
336
337
253
on_error:
338
253
    free(buf);
339
253
    return 1;
340
62
}
341
342
343
static void
344
sun_close(TSK_VS_INFO * vs)
345
584
{
346
584
    vs->tag = 0;
347
584
    tsk_vs_part_free(vs);
348
584
    free(vs);
349
584
}
350
351
TSK_VS_INFO *
352
tsk_vs_sun_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset)
353
584
{
354
584
    TSK_VS_INFO *vs;
355
356
    // clean up any errors that are lying around
357
584
    tsk_error_reset();
358
359
584
    if (img_info->sector_size == 0) {
360
0
        tsk_error_reset();
361
0
        tsk_error_set_errno(TSK_ERR_VS_ARG);
362
0
        tsk_error_set_errstr("tsk_vs_sun_open: sector size is 0");
363
0
        return NULL;
364
0
    }
365
366
584
    vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs));
367
584
    if (vs == NULL)
368
0
        return NULL;
369
370
584
    vs->img_info = img_info;
371
584
    vs->vstype = TSK_VS_TYPE_SUN;
372
584
    vs->tag = TSK_VS_INFO_TAG;
373
374
584
    vs->offset = offset;
375
376
    /* initialize settings */
377
584
    vs->part_list = NULL;
378
584
    vs->part_count = 0;
379
584
    vs->endian = 0;
380
584
    vs->block_size = img_info->sector_size;
381
382
    /* Assign functions */
383
584
    vs->close = sun_close;
384
385
    /* Load the partitions into the sorted list */
386
584
    if (sun_load_table(vs)) {
387
342
        sun_close(vs);
388
342
        return NULL;
389
342
    }
390
391
    /* fill in the sorted list with the 'unknown' values */
392
242
    if (tsk_vs_part_unused(vs)) {
393
0
        sun_close(vs);
394
0
        return NULL;
395
0
    }
396
397
242
    return vs;
398
242
}