Coverage Report

Created: 2025-08-29 06:55

/src/sleuthkit/tsk/fs/iso9660_dent.cpp
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)2007 Brian Carrier.  All righs reserved.
6
**
7
**
8
** This software is subject to the IBM Public License ver. 1.0,
9
** which was displayed prior to download and is included in the readme.txt
10
** file accompanying the Sleuth Kit files.  It may also be requested from:
11
** Crucial Security Inc.
12
** 14900 Conference Center Drive
13
** Chantilly, VA 20151
14
**
15
** Copyright (c) 2007-2011 Brian Carrier.  All rights reserved
16
**
17
** Wyatt Banks [wbanks@crucialsecurity.com]
18
** Copyright (c) 2005 Crucial Security Inc.  All rights reserved.
19
**
20
** Brian Carrier [carrier <at> sleuthkit [dot] org]
21
** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
22
**
23
** Copyright (c) 1997,1998,1999, International Business Machines
24
** Corporation and others. All Rights Reserved.
25
*/
26
27
/* TCT
28
 * LICENSE
29
 *      This software is distributed under the IBM Public License.
30
 * AUTHOR(S)
31
 *      Wietse Venema
32
 *      IBM T.J. Watson Research
33
 *      P.O. Box 704
34
 *      Yorktown Heights, NY 10598, USA
35
 --*/
36
37
/*
38
** You may distribute the Sleuth Kit, or other software that incorporates
39
** part of all of the Sleuth Kit, in object code form under a license agreement,
40
** provided that:
41
** a) you comply with the terms and conditions of the IBM Public License
42
**    ver 1.0; and
43
** b) the license agreement
44
**     i) effectively disclaims on behalf of all Contributors all warranties
45
**        and conditions, express and implied, including warranties or
46
**        conditions of title and non-infringement, and implied warranties
47
**        or conditions of merchantability and fitness for a particular
48
**        purpose.
49
**    ii) effectively excludes on behalf of all Contributors liability for
50
**        damages, including direct, indirect, special, incidental and
51
**        consequential damages such as lost profits.
52
**   iii) states that any provisions which differ from IBM Public License
53
**        ver. 1.0 are offered by that Contributor alone and not by any
54
**        other party; and
55
**    iv) states that the source code for the program is available from you,
56
**        and informs licensees how to obtain it in a reasonable manner on or
57
**        through a medium customarily used for software exchange.
58
**
59
** When the Sleuth Kit or other software that incorporates part or all of
60
** the Sleuth Kit is made available in source code form:
61
**     a) it must be made available under IBM Public License ver. 1.0; and
62
**     b) a copy of the IBM Public License ver. 1.0 must be included with
63
**        each copy of the program.
64
*/
65
66
/**
67
 * \file iso9660_dent.c
68
 * Contains the internal TSK ISO9660 file system code to handle the parsing of
69
 * file names and directory structures.
70
 */
71
72
#include "tsk_fs_i.h"
73
#include "tsk_iso9660.h"
74
75
76
77
/** \internal
78
 * process the data from inside of a directory and load the corresponding
79
 * file data into a TSK_FS_DIR structure.
80
 *
81
 * @param a_fs File system
82
 * @param a_fs_dir Structure to store file names into
83
 * @param buf Buffer that contains the directory content
84
 * @param a_length Number of bytes in buffer
85
 * @param a_addr The metadata address for the directory being processed
86
 * @param a_dir_addr The block offset where this directory starts
87
 * @returns TSK_ERR on error and TSK_OK otherwise
88
 */
89
static TSK_RETVAL_ENUM
90
iso9660_proc_dir(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir, const char *buf,
91
    size_t a_length, TSK_INUM_T a_addr, TSK_OFF_T a_dir_addr)
92
154k
{
93
154k
    ISO_INFO *iso = (ISO_INFO *) a_fs;
94
154k
    TSK_FS_NAME *fs_name;
95
154k
    size_t buf_idx;
96
97
154k
    iso9660_dentry *dd;         /* directory descriptor */
98
154k
    iso9660_inode_node *in;
99
154k
    TSK_OFF_T dir_offs = a_dir_addr * a_fs->block_size;
100
101
    // had an issue once where dir was too small
102
    // many later calculations assume we can fit at least one entry
103
154k
    if (a_length < sizeof(iso9660_dentry)) {
104
3.31k
        return TSK_OK;
105
3.31k
    }
106
107
150k
    if ((fs_name = tsk_fs_name_alloc(ISO9660_MAXNAMLEN + 1, 0)) == NULL)
108
0
        return TSK_ERR;
109
110
150k
    buf_idx = 0;
111
150k
    dd = (iso9660_dentry *) & buf[buf_idx];
112
113
    /* handle "." entry */
114
150k
    fs_name->meta_addr = a_addr;
115
150k
    strcpy(fs_name->name, ".");
116
150k
    fs_name->type = TSK_FS_NAME_TYPE_DIR;
117
150k
    fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
118
119
150k
    tsk_fs_dir_add(a_fs_dir, fs_name);
120
121
150k
    buf_idx += dd->entry_len;
122
150k
    if (buf_idx > a_length - sizeof(iso9660_dentry)) {
123
3.21k
        tsk_fs_name_free(fs_name);
124
3.21k
        return TSK_OK;
125
3.21k
    }
126
147k
    dd = (iso9660_dentry *) & buf[buf_idx];
127
128
    /* handle ".." entry */
129
147k
    in = iso->in_list;
130
2.19M
    while (in
131
2.19M
        && (tsk_getu32(a_fs->endian, in->inode.dr.ext_loc_m) !=
132
2.08M
            tsk_getu32(a_fs->endian, dd->ext_loc_m)))
133
2.05M
        in = in->next;
134
147k
    if (in) {
135
29.6k
        fs_name->meta_addr = in->inum;
136
29.6k
        strcpy(fs_name->name, "..");
137
138
29.6k
        fs_name->type = TSK_FS_NAME_TYPE_DIR;
139
29.6k
        fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
140
141
29.6k
        tsk_fs_dir_add(a_fs_dir, fs_name);
142
29.6k
    }
143
147k
    buf_idx += dd->entry_len;
144
145
    // process the rest of the entries in the directory
146
968M
    while (buf_idx < a_length - sizeof(iso9660_dentry)) {
147
968M
        dd = (iso9660_dentry *) & buf[buf_idx];
148
149
        // process the entry (if it has a defined and valid length)
150
968M
        if ((dd->entry_len) && (buf_idx + dd->entry_len <= a_length)) {
151
152
            /* We need to find the data in the pre-processed list because that
153
             * contains the meta data address that TSK assigned to this file.
154
             * We find the entry by looking for one that was stored at the same
155
             * byte offset that we now are.  We used to use the extent location, but
156
             * we found an image
157
             * that had a file with 0 bytes with the same starting block as another
158
             * file. */
159
24.4G
            for (in = iso->in_list; in; in = in->next) {
160
23.9G
                if (in->dentry_offset == dir_offs + (TSK_OFF_T)buf_idx)
161
840k
                    break;
162
23.9G
            }
163
164
            // we may have not found it because we are reading corrupt data...
165
542M
            if (!in) {
166
541M
                buf_idx++;
167
541M
                continue;
168
541M
            }
169
170
            // copy the data in fs_name for loading
171
840k
            fs_name->meta_addr = in->inum;
172
840k
            strncpy(fs_name->name, in->inode.fn, ISO9660_MAXNAMLEN + 1);
173
174
840k
            if (dd->flags & ISO9660_FLAG_DIR)
175
544k
                fs_name->type = TSK_FS_NAME_TYPE_DIR;
176
295k
            else
177
295k
                fs_name->type = TSK_FS_NAME_TYPE_REG;
178
840k
            fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
179
180
840k
            tsk_fs_dir_add(a_fs_dir, fs_name);
181
182
840k
            buf_idx += dd->entry_len;
183
840k
        }
184
        /* If the length was not defined, we are probably in a hole in the
185
         * directory.  The contents are  block aligned. So, we
186
         * scan ahead until we get either a non-zero entry or the block boundary */
187
426M
        else {
188
426M
            buf_idx++;
189
1.05G
            for (; buf_idx < a_length - sizeof(iso9660_dentry); buf_idx++) {
190
1.05G
                if (buf[buf_idx] != 0) {
191
29.4M
                    dd = (iso9660_dentry *) & buf[buf_idx];
192
29.4M
                    if ((dd->entry_len)
193
29.4M
                        && (buf_idx + dd->entry_len < a_length))
194
27.3M
                        break;
195
29.4M
                }
196
197
1.03G
                if (buf_idx % a_fs->block_size == 0)
198
398M
                    break;
199
1.03G
            }
200
426M
        }
201
968M
    }
202
203
147k
    tsk_fs_name_free(fs_name);
204
205
147k
    return TSK_OK;
206
150k
}
207
208
209
210
/** \internal
211
 * Process a directory and load up FS_DIR with the entries. If a pointer to
212
 * an already allocated FS_DIR structure is given, it will be cleared.  If no existing
213
 * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return
214
 * value is error or corruption, then the FS_DIR structure could
215
 * have entries (depending on when the error occurred).
216
 *
217
 * @param a_fs File system to analyze
218
 * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated
219
 * structure or a new structure.
220
 * @param a_addr Address of directory to process.
221
 * @param recursion_depth Recursion depth to limit the number of self-calls
222
 * @returns error, corruption, ok etc.
223
 */
224
TSK_RETVAL_ENUM
225
iso9660_dir_open_meta(
226
  TSK_FS_INFO * a_fs,
227
  TSK_FS_DIR ** a_fs_dir,
228
  TSK_INUM_T a_addr,
229
  [[maybe_unused]] int recursion_depth)
230
247k
{
231
247k
    TSK_RETVAL_ENUM retval;
232
247k
    TSK_FS_DIR *fs_dir;
233
247k
    ssize_t cnt;
234
247k
    char *buf;
235
247k
    size_t length;
236
237
247k
    if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) {
238
0
        tsk_error_reset();
239
0
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
240
0
        tsk_error_set_errstr
241
0
            ("iso9660_dir_open_meta: Invalid inode value: %" PRIuINUM,
242
0
            a_addr);
243
0
        return TSK_ERR;
244
0
    }
245
247k
    else if (a_fs_dir == NULL) {
246
0
        tsk_error_reset();
247
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
248
0
        tsk_error_set_errstr
249
0
            ("iso9660_dir_open_meta: NULL fs_attr argument given");
250
0
        return TSK_ERR;
251
0
    }
252
253
247k
    if (tsk_verbose)
254
0
        tsk_fprintf(stderr,
255
0
            "iso9660_dir_open_meta: Processing directory %" PRIuINUM "\n",
256
0
            a_addr);
257
258
247k
    fs_dir = *a_fs_dir;
259
247k
    if (fs_dir) {
260
0
        tsk_fs_dir_reset(fs_dir);
261
0
        fs_dir->addr = a_addr;
262
0
    }
263
247k
    else {
264
247k
        if ((*a_fs_dir = fs_dir =
265
247k
                tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) {
266
0
            return TSK_ERR;
267
0
        }
268
247k
    }
269
270
    //  handle the orphan directory if its contents were requested
271
247k
    if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) {
272
3.92k
        return tsk_fs_dir_find_orphans(a_fs, fs_dir);
273
3.92k
    }
274
275
243k
    fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr);
276
243k
    if (fs_dir->fs_file == NULL) {
277
8
        tsk_error_reset();
278
8
        tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
279
8
        tsk_error_set_errstr("iso9660_dir_open_meta: %" PRIuINUM
280
8
            " is not a valid inode", a_addr);
281
8
        return TSK_COR;
282
8
    }
283
284
    /* read directory extent into memory */
285
243k
    length = (size_t) fs_dir->fs_file->meta->size;
286
243k
    if ((buf = (char*) tsk_malloc(length)) == NULL)
287
0
        return TSK_ERR;
288
289
243k
    cnt = tsk_fs_file_read(fs_dir->fs_file, 0, buf, length, TSK_FS_FILE_READ_FLAG_NONE);
290
243k
    if (cnt != (ssize_t)length) {
291
89.3k
        if (cnt >= 0) {
292
47.7k
            tsk_error_reset();
293
47.7k
            tsk_error_set_errno(TSK_ERR_FS_READ);
294
47.7k
        }
295
89.3k
        tsk_error_set_errstr2("iso9660_dir_open_meta");
296
89.3k
        free(buf);
297
89.3k
        return TSK_ERR;
298
89.3k
    }
299
300
    // process the contents
301
154k
    retval = iso9660_proc_dir(a_fs, fs_dir, buf, length, a_addr,
302
154k
        fs_dir->fs_file->meta->attr->head->nrd.run->addr);
303
304
    // if we are listing the root directory, add the Orphan directory entry
305
154k
    if (a_addr == a_fs->root_inum) {
306
18.1k
        TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0);
307
18.1k
        if (fs_name == NULL) {
308
0
            free(buf);
309
0
            return TSK_ERR;
310
0
        }
311
312
18.1k
        if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) {
313
0
            tsk_fs_name_free(fs_name);
314
0
            free(buf);
315
0
            return TSK_ERR;
316
0
        }
317
318
18.1k
        if (tsk_fs_dir_add(fs_dir, fs_name)) {
319
0
            tsk_fs_name_free(fs_name);
320
0
            free(buf);
321
0
            return TSK_ERR;
322
0
        }
323
18.1k
        tsk_fs_name_free(fs_name);
324
18.1k
    }
325
326
154k
    free(buf);
327
154k
    return retval;
328
154k
}
329
330
int
331
iso9660_name_cmp(
332
  [[maybe_unused]] TSK_FS_INFO * a_fs_info,
333
  const char *s1,
334
  const char *s2)
335
0
{
336
0
    return strcmp(s1, s2);
337
0
}