Coverage Report

Created: 2025-07-18 07:03

/src/sleuthkit/tsk/vs/sun.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) 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
0
{
26
0
    char *str = tsk_malloc(64);
27
0
    if (str == NULL)
28
0
        return "";
29
0
    switch (fstype) {
30
31
0
    case 0:
32
0
        strncpy(str, "Unassigned (0x00)", 64);
33
0
        break;
34
0
    case 1:
35
0
        strncpy(str, "boot (0x01)", 64);
36
0
        break;
37
0
    case 2:
38
0
        strncpy(str, "/ (0x02)", 64);
39
0
        break;
40
0
    case 3:
41
0
        strncpy(str, "swap (0x03)", 64);
42
0
        break;
43
0
    case 4:
44
0
        strncpy(str, "/usr/ (0x04)", 64);
45
0
        break;
46
0
    case 5:
47
0
        strncpy(str, "backup (0x05)", 64);
48
0
        break;
49
0
    case 6:
50
0
        strncpy(str, "stand (0x06)", 64);
51
0
        break;
52
0
    case 7:
53
0
        strncpy(str, "/var/ (0x07)", 64);
54
0
        break;
55
0
    case 8:
56
0
        strncpy(str, "/home/ (0x08)", 64);
57
0
        break;
58
0
    case 9:
59
0
        strncpy(str, "alt sector (0x09)", 64);
60
0
        break;
61
0
    case 10:
62
0
        strncpy(str, "cachefs (0x0A)", 64);
63
0
        break;
64
0
    default:
65
0
        snprintf(str, 64, "Unknown Type (0x%.4x)", fstype);
66
0
        break;
67
0
    }
68
69
0
    return str;
70
0
}
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
0
{
80
0
    uint32_t idx = 0;
81
0
    uint16_t num_parts;
82
0
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector
83
84
0
    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
0
    num_parts = tsk_getu16(vs->endian, dlabel_x86->num_parts);
89
0
    if (num_parts > 16) {
90
0
        num_parts = 16;
91
0
    }
92
93
    /* Cycle through the partitions, there are 16 for i386 */
94
0
    for (idx = 0; idx < num_parts; idx++) {
95
0
        TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
96
97
0
        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
0
        if (tsk_getu32(vs->endian, dlabel_x86->part[idx].size_sec) == 0)
107
0
            continue;
108
109
        // make sure the first couple are in the image bounds
110
0
        if ((idx < 2) && (tsk_getu32(vs->endian,
111
0
                    dlabel_x86->part[idx].start_sec) > max_addr)) {
112
0
            tsk_error_reset();
113
0
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
114
0
            tsk_error_set_errstr
115
0
                ("sun_load_i386: Starting sector too large for image");
116
0
            return 1;
117
0
        }
118
119
        // set the entry that covers the entire disk image as DESC
120
0
        if ((tsk_getu16(vs->endian, dlabel_x86->part[idx].type) == 5)
121
0
            && (tsk_getu32(vs->endian,
122
0
                    dlabel_x86->part[idx].start_sec) == 0))
123
0
            ptype = TSK_VS_PART_FLAG_META;
124
125
        /* Add the partition to the internal sorted list */
126
0
        if (NULL == tsk_vs_part_add(vs,
127
0
                (TSK_DADDR_T) tsk_getu32(vs->endian,
128
0
                    dlabel_x86->part[idx].start_sec),
129
0
                (TSK_DADDR_T) tsk_getu32(vs->endian,
130
0
                    dlabel_x86->part[idx].size_sec), ptype,
131
0
                sun_get_desc(tsk_getu16(vs->endian,
132
0
                        dlabel_x86->part[idx].type)), -1, idx)) {
133
0
            return 1;
134
0
        }
135
0
    }
136
137
0
    return 0;
138
0
}
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
0
{
147
0
    uint32_t idx = 0;
148
0
    uint32_t cyl_conv;
149
0
    uint16_t num_parts;
150
0
    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
0
    cyl_conv = (uint32_t) tsk_getu16(vs->endian, dlabel_sp->sec_per_tr) *
154
0
        tsk_getu16(vs->endian, dlabel_sp->num_head);
155
156
0
    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
0
    num_parts = tsk_getu16(vs->endian, dlabel_sp->num_parts);
161
0
    if (num_parts > 8) {
162
0
        num_parts = 8;
163
0
    }
164
165
    /* Cycle through the partitions, there are 8 for sparc */
166
0
    for (idx = 0; idx < num_parts; idx++) {
167
0
        TSK_VS_PART_FLAG_ENUM ptype = TSK_VS_PART_FLAG_ALLOC;
168
0
        uint32_t part_start = cyl_conv * tsk_getu32(vs->endian,
169
0
            dlabel_sp->part_layout[idx].start_cyl);
170
171
0
        uint32_t part_size = tsk_getu32(vs->endian,
172
0
            dlabel_sp->part_layout[idx].size_blk);
173
174
0
        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
0
        if (part_size == 0)
182
0
            continue;
183
184
        // make sure the first couple are in the image bounds
185
0
        if ((idx < 2) && (part_start > max_addr)) {
186
0
            tsk_error_reset();
187
0
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
188
0
            tsk_error_set_errstr
189
0
                ("sun_load_sparc: Starting sector too large for image");
190
0
            return 1;
191
0
        }
192
193
        // set the entry that covers the entire disk image as DESC
194
0
        if ((tsk_getu16(vs->endian, dlabel_sp->part_meta[idx].type) == 5)
195
0
            && (part_start == 0))
196
0
            ptype = TSK_VS_PART_FLAG_META;
197
198
        /* Add the partition to the internal sorted list */
199
0
        if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
200
0
                (TSK_DADDR_T) part_size, ptype,
201
0
                sun_get_desc(tsk_getu16(vs->endian,
202
0
                        dlabel_sp->part_meta[idx].type)), -1, idx))
203
0
            return 1;
204
205
0
    }
206
207
0
    return 0;
208
0
}
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
0
{
222
0
    sun_dlabel_sparc *dlabel_sp;
223
0
    sun_dlabel_i386 *dlabel_x86;
224
0
    char *buf;
225
0
    ssize_t cnt;
226
0
    TSK_DADDR_T taddr =
227
0
        vs->offset / vs->block_size + SUN_SPARC_PART_SOFFSET;
228
0
    int result = 0;
229
230
231
    /* Sanity check in case label sizes change */
232
0
    if ((sizeof(*dlabel_sp) > vs->block_size) ||
233
0
        (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
0
    if (tsk_verbose)
242
0
        tsk_fprintf(stderr,
243
0
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr);
244
245
0
    if ((buf = tsk_malloc(vs->block_size)) == NULL) {
246
0
        goto on_error;
247
0
    }
248
249
    /* Try the given offset */
250
0
    cnt = tsk_vs_read_block
251
0
        (vs, SUN_SPARC_PART_SOFFSET, buf, vs->block_size);
252
253
    /* If -1 is returned, tsk_errno is already set */
254
0
    if (cnt != vs->block_size) {
255
0
        if (cnt >= 0) {
256
0
            tsk_error_reset();
257
0
            tsk_error_set_errno(TSK_ERR_VS_READ);
258
0
        }
259
0
        tsk_error_set_errstr2("SUN Disk Label in Sector: %" PRIuDADDR,
260
0
            taddr);
261
0
        goto on_error;
262
0
    }
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
0
    dlabel_sp = (sun_dlabel_sparc *) buf;
272
0
    dlabel_x86 = (sun_dlabel_i386 *) buf;
273
0
    if (tsk_vs_guessu16(vs, dlabel_sp->magic, SUN_MAGIC) == 0) {
274
0
        if (tsk_getu32(vs->endian, dlabel_sp->sanity) == SUN_SANITY) {
275
0
            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
0
            free(buf);
279
0
            return result;
280
0
        }
281
0
        else if (tsk_getu32(vs->endian, dlabel_x86->sanity) == SUN_SANITY) {
282
0
            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
0
            free(buf);
286
0
            return result;
287
0
        }
288
0
    }
289
290
291
    /* Now try the next sector, which is where the intel
292
     * could be stored */
293
294
0
    taddr = vs->offset / vs->block_size / SUN_I386_PART_SOFFSET;
295
0
    if (tsk_verbose)
296
0
        tsk_fprintf(stderr,
297
0
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr + 1);
298
299
0
    cnt = tsk_vs_read_block
300
0
        (vs, SUN_I386_PART_SOFFSET, buf, vs->block_size);
301
302
0
    if (cnt != vs->block_size) {
303
0
        if (cnt >= 0) {
304
0
            tsk_error_reset();
305
0
            tsk_error_set_errno(TSK_ERR_VS_READ);
306
0
        }
307
0
        tsk_error_set_errstr2("SUN (Intel) Disk Label in Sector: %"
308
0
            PRIuDADDR, taddr);
309
0
        goto on_error;
310
0
    }
311
312
0
    dlabel_x86 = (sun_dlabel_i386 *) buf;
313
0
    if (tsk_vs_guessu16(vs, dlabel_x86->magic, SUN_MAGIC)) {
314
0
        tsk_error_reset();
315
0
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
316
0
        tsk_error_set_errstr("SUN (intel) partition table (Sector: %"
317
0
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
318
0
                dlabel_sp->magic));
319
0
        goto on_error;
320
0
    }
321
322
0
    if (tsk_getu32(vs->endian, dlabel_x86->sanity) != SUN_SANITY) {
323
0
        tsk_error_reset();
324
0
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
325
0
        tsk_error_set_errstr("SUN (intel) sanity value (Sector: %"
326
0
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
327
0
                dlabel_sp->magic));
328
0
        goto on_error;
329
0
    }
330
331
0
    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
0
    free(buf);
335
0
    return result;
336
337
0
on_error:
338
0
    free(buf);
339
0
    return 1;
340
0
}
341
342
343
static void
344
sun_close(TSK_VS_INFO * vs)
345
0
{
346
0
    vs->tag = 0;
347
0
    tsk_vs_part_free(vs);
348
0
    free(vs);
349
0
}
350
351
TSK_VS_INFO *
352
tsk_vs_sun_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset)
353
0
{
354
0
    TSK_VS_INFO *vs;
355
356
    // clean up any errors that are lying around
357
0
    tsk_error_reset();
358
359
0
    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
0
    vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs));
367
0
    if (vs == NULL)
368
0
        return NULL;
369
370
0
    vs->img_info = img_info;
371
0
    vs->vstype = TSK_VS_TYPE_SUN;
372
0
    vs->tag = TSK_VS_INFO_TAG;
373
374
0
    vs->offset = offset;
375
376
    /* initialize settings */
377
0
    vs->part_list = NULL;
378
0
    vs->part_count = 0;
379
0
    vs->endian = 0;
380
0
    vs->block_size = img_info->sector_size;
381
382
    /* Assign functions */
383
0
    vs->close = sun_close;
384
385
    /* Load the partitions into the sorted list */
386
0
    if (sun_load_table(vs)) {
387
0
        sun_close(vs);
388
0
        return NULL;
389
0
    }
390
391
    /* fill in the sorted list with the 'unknown' values */
392
0
    if (tsk_vs_part_unused(vs)) {
393
0
        sun_close(vs);
394
0
        return NULL;
395
0
    }
396
397
0
    return vs;
398
0
}