diff --git a/CHANGES.txt b/CHANGES.txt index d6c85480fdc36e304e07301fa411146320add1c0..dd140addb49479697308018647561d1a0535d428 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -95,6 +95,9 @@ to sigfind. 7/13/09: Bug Fix: Fixed issue 2821031 re: missing fls -m fields. +7/21/09: Update: Resolved Feature request 2206331 re: indirect blocks +in UFS/Ext2. + ---------------- VERSION 3.0.1 -------------- 11/11/08: Bug Fix: Fixed crashing bug in ifind on FAT file system. diff --git a/tsk3/fs/ext2fs.c b/tsk3/fs/ext2fs.c index e2e9634c9c9094d2c32f3c2424ebcd4e299fd7e2..2a341f5b6f877be0f066271349dcee8539cfd627 100644 --- a/tsk3/fs/ext2fs.c +++ b/tsk3/fs/ext2fs.c @@ -111,8 +111,7 @@ ext2fs_group_load(EXT2FS_INFO * ext2fs, EXT2_GRPNUM_T grp_num) tsk_fprintf(stderr, "\tgroup %" PRI_EXT2GRP ": %" PRIu16 "/%" PRIu16 " free blocks/inodes\n", grp_num, tsk_getu16(fs->endian, - gd-> - bg_free_blocks_count), + gd->bg_free_blocks_count), tsk_getu16(fs->endian, gd->bg_free_inodes_count)); } @@ -1375,8 +1374,7 @@ ext2fs_fsstat(TSK_FS_INFO * fs, FILE * hFile) (cg_base != tsk_getu32(fs->endian, ext2fs->grp_buf->bg_block_bitmap))) || ((tsk_getu32(fs->endian, - ext2fs->fs-> - s_feature_ro_compat) & + ext2fs->fs->s_feature_ro_compat) & EXT2FS_FEATURE_RO_COMPAT_SPARSE_SUPER) == 0)) { TSK_OFF_T boff; @@ -1597,6 +1595,7 @@ ext2fs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, TSK_FS_FILE *fs_file; char ls[12]; EXT2FS_PRINT_ADDR print; + const TSK_FS_ATTR *fs_attr_indir; // clean up any error messages that are lying around tsk_error_reset(); @@ -1958,6 +1957,24 @@ ext2fs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, tsk_fprintf(hFile, "\n"); } + fs_attr_indir = tsk_fs_file_attr_get_type(fs_file, + TSK_FS_ATTR_TYPE_UNIX_INDIR, 0, 0); + if (fs_attr_indir) { + tsk_fprintf(hFile, "\nIndirect Blocks:\n"); + + print.idx = 0; + + if (tsk_fs_attr_walk(fs_attr_indir, TSK_FS_FILE_WALK_FLAG_AONLY, + print_addr_act, (void *) &print)) { + tsk_fprintf(hFile, "\nError reading indirect attribute: "); + tsk_error_print(hFile); + tsk_error_reset(); + } + else if (print.idx != 0) { + tsk_fprintf(hFile, "\n"); + } + } + tsk_fs_file_close(fs_file); return 0; } @@ -2230,8 +2247,7 @@ ext2fs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset, tsk_fprintf(stderr, "inodes %" PRIu32 " root ino %" PRIuINUM " blocks %" PRIu32 " blocks/group %" PRIu32 "\n", tsk_getu32(fs->endian, - ext2fs->fs-> - s_inodes_count), + ext2fs->fs->s_inodes_count), fs->root_inum, tsk_getu32(fs->endian, ext2fs->fs->s_blocks_count), tsk_getu32(fs->endian, ext2fs->fs->s_blocks_per_group)); diff --git a/tsk3/fs/ffs.c b/tsk3/fs/ffs.c index 6df6df319651ba7870b505826464c7f32aaa9bdd..3887cfa4254ab68c004829cdfd03d5b6cabe7a50 100644 --- a/tsk3/fs/ffs.c +++ b/tsk3/fs/ffs.c @@ -1642,6 +1642,7 @@ ffs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, TSK_FS_FILE *fs_file; char ls[12]; FFS_PRINT_ADDR print; + const TSK_FS_ATTR *fs_attr_indir; // clean up any error messages that are lying around tsk_error_reset(); @@ -1825,6 +1826,24 @@ ffs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum, if (print.idx != 0) tsk_fprintf(hFile, "\n"); + fs_attr_indir = tsk_fs_file_attr_get_type(fs_file, + TSK_FS_ATTR_TYPE_UNIX_INDIR, 0, 0); + if (fs_attr_indir) { + tsk_fprintf(hFile, "\nIndirect Blocks:\n"); + + print.idx = 0; + + if (tsk_fs_attr_walk(fs_attr_indir, TSK_FS_FILE_WALK_FLAG_AONLY, + print_addr_act, (void *) &print)) { + tsk_fprintf(hFile, "\nError reading indirect attribute: "); + tsk_error_print(hFile); + tsk_error_reset(); + } + else if (print.idx != 0) { + tsk_fprintf(hFile, "\n"); + } + } + tsk_fs_file_close(fs_file); return 0; } diff --git a/tsk3/fs/fs_attrlist.c b/tsk3/fs/fs_attrlist.c index a31e9548d32118909fa205a88c011f4582330273..7dc2106afae14e1c4bb1ae33990b81b0d53b0b46 100644 --- a/tsk3/fs/fs_attrlist.c +++ b/tsk3/fs/fs_attrlist.c @@ -167,7 +167,8 @@ tsk_fs_attrlist_getnew(TSK_FS_ATTRLIST * a_fs_attrlist, return NULL; // add it to the list - tsk_fs_attrlist_add(a_fs_attrlist, fs_attr_cur); + if (tsk_fs_attrlist_add(a_fs_attrlist, fs_attr_cur)) + return NULL; } } diff --git a/tsk3/fs/ifind_lib.c b/tsk3/fs/ifind_lib.c index bbfadbaec51ed8f09a320c8ef9c14923645f5257..e0e75ebe3f684ef272d13a0c7e685614643532b1 100644 --- a/tsk3/fs/ifind_lib.c +++ b/tsk3/fs/ifind_lib.c @@ -552,13 +552,12 @@ ifind_data_act(TSK_FS_FILE * fs_file, void *ptr) data->curtype = fs_attr->type; data->curid = fs_attr->id; if (fs_attr->flags & TSK_FS_ATTR_NONRES) { - if (tsk_fs_file_walk_type(fs_file, fs_attr->type, - fs_attr->id, file_flags, ifind_data_file_ntfs_act, - ptr)) { + if (tsk_fs_attr_walk(fs_attr, + file_flags, ifind_data_file_ntfs_act, ptr)) { if (tsk_verbose) tsk_fprintf(stderr, - "Error walking file %" PRIuINUM, - fs_file->meta->addr); + "Error walking file %" PRIuINUM + " Attribute: %i", fs_file->meta->addr, i); /* Ignore these errors */ tsk_error_reset(); @@ -584,7 +583,8 @@ ifind_data_act(TSK_FS_FILE * fs_file, void *ptr) * correlated with the incorrect inode */ else { - // @@@ Need to add handling back in here to find indirect blocks (once a soln is found) + const TSK_FS_ATTR *fs_attr; + if (tsk_fs_file_walk(fs_file, file_flags, ifind_data_file_act, ptr)) { if (tsk_verbose) @@ -594,6 +594,25 @@ ifind_data_act(TSK_FS_FILE * fs_file, void *ptr) /* Ignore these errors */ tsk_error_reset(); } + + + // try the indirect blocks + fs_attr = tsk_fs_file_attr_get_type(fs_file, + TSK_FS_ATTR_TYPE_UNIX_INDIR, 0, 0); + if (fs_attr) { + data->curtype = fs_attr->type; + data->curid = fs_attr->id; + + if (tsk_fs_attr_walk(fs_attr, + file_flags, ifind_data_file_act, ptr)) { + if (tsk_verbose) + tsk_fprintf(stderr, + "Error walking file %" PRIuINUM + " Indirect Attribute", fs_file->meta->addr); + /* Ignore these errors */ + tsk_error_reset(); + } + } } return TSK_WALK_CONT; diff --git a/tsk3/fs/tsk_fs.h b/tsk3/fs/tsk_fs.h index c6f8a0ffd98c516d0b873739ec67d47ada2badf6..160d1f97a166d9c3c20664f8f9608c5ebcae7b36 100644 --- a/tsk3/fs/tsk_fs.h +++ b/tsk3/fs/tsk_fs.h @@ -201,7 +201,7 @@ extern "C" { * These are based on the NTFS type values. */ typedef enum { - TSK_FS_ATTR_TYPE_DEFAULT = 0x0, // 16 + TSK_FS_ATTR_TYPE_DEFAULT = 0x01, // 1 TSK_FS_ATTR_TYPE_NTFS_SI = 0x10, // 16 TSK_FS_ATTR_TYPE_NTFS_ATTRLIST = 0x20, // 32 TSK_FS_ATTR_TYPE_NTFS_FNAME = 0x30, // 48 @@ -219,7 +219,8 @@ extern "C" { TSK_FS_ATTR_TYPE_NTFS_EAINFO = 0xD0, // 208 TSK_FS_ATTR_TYPE_NTFS_EA = 0xE0, // 224 TSK_FS_ATTR_TYPE_NTFS_PROP = 0xF0, // (NT) - TSK_FS_ATTR_TYPE_NTFS_LOG = 0x100 // (2K) + TSK_FS_ATTR_TYPE_NTFS_LOG = 0x100, // (2K) + TSK_FS_ATTR_TYPE_UNIX_INDIR = 0x1001 // Indirect blocks for UFS and ExtX file systems } TSK_FS_ATTR_TYPE_ENUM; #define TSK_FS_ATTR_ID_DEFAULT 0 ///< Default Data ID used if file system does not assign one. diff --git a/tsk3/fs/unix_misc.c b/tsk3/fs/unix_misc.c index cc5f94b03e1115de5a293c537e8196583facd6ec..24b26d9bf45f907d280d3d50ac085afcdd9ecdeb 100644 --- a/tsk3/fs/unix_misc.c +++ b/tsk3/fs/unix_misc.c @@ -109,6 +109,7 @@ unix_make_data_run_direct(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, * * @param fs File system to analyze * @param fs_attr Structure to save run data into + * @param fs_attr_indir Structure to save addresses of indirect block pointers in * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type) * @param level Indirection level that this will process at (1+) * @param addr Address of block to read @@ -118,7 +119,8 @@ unix_make_data_run_direct(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, */ static TSK_OFF_T unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, - char *buf[], int level, TSK_DADDR_T addr, TSK_OFF_T length) + TSK_FS_ATTR * fs_attr_indir, char *buf[], int level, TSK_DADDR_T addr, + TSK_OFF_T length) { char *myname = "unix_make_data_run_indirect"; size_t addr_cnt = 0; @@ -126,17 +128,21 @@ unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, TSK_OFF_T length_remain = length; TSK_OFF_T retval; size_t fs_bufsize; + size_t fs_blen; + TSK_FS_ATTR_RUN *data_run; if (tsk_verbose) tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", myname, level, addr); + // block_size is a fragment size in UFS, so we need to maintain length in fragments if (TSK_FS_TYPE_ISFFS(fs->ftype)) { FFS_INFO *ffs = (FFS_INFO *) fs; - + fs_blen = ffs->ffsbsize_f; fs_bufsize = ffs->ffsbsize_b; } else { + fs_blen = 1; fs_bufsize = fs->block_size; } @@ -149,12 +155,21 @@ unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, return -1; } + // make a non-resident run + data_run = tsk_fs_attr_run_alloc(); + if (data_run == NULL) + return -1; + + data_run->addr = addr; + data_run->len = fs_blen; + /* * Read a block of disk addresses. */ // sparse if (addr == 0) { memset(buf[0], 0, fs_bufsize); + data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE; } else { ssize_t cnt; @@ -169,10 +184,11 @@ unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, "unix_make_data_run_indir: Block %" PRIuDADDR, addr); return -1; } - - // @@@ what do we do about META.... } + // save the run + tsk_fs_attr_append_run(fs, fs_attr_indir, data_run); + // convert the raw addresses to the correct endian ordering if ((fs->ftype == TSK_FS_TYPE_FFS1) || (fs->ftype == TSK_FS_TYPE_FFS1B) @@ -207,8 +223,8 @@ unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr, retval = 0; for (i = 0; i < addr_cnt && retval != -1; i++) { retval = - unix_make_data_run_indirect(fs, fs_attr, buf, level - 1, - myaddrs[i], length_remain); + unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir, + buf, level - 1, myaddrs[i], length_remain); if (retval == -1) { break; } @@ -235,6 +251,7 @@ tsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file) TSK_OFF_T length = 0; TSK_OFF_T read_b = 0; TSK_FS_ATTR *fs_attr; + TSK_FS_ATTR *fs_attr_indir; TSK_FS_META *fs_meta = fs_file->meta; TSK_FS_INFO *fs = fs_file->fs_info; @@ -304,6 +321,12 @@ tsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file) char **buf; size_t fs_bufsize0; size_t fs_bufsize1; + int ptrsperblock; + int numBlocks = 0; + int numSingIndirect = 0; + int numDblIndirect = 0; + int numTripIndirect = 0; + /* With FFS/UFS a full block contains the addresses, but block_size is * only a fragment. Figure out the scratch buffer size and the buffers to @@ -313,15 +336,18 @@ tsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file) fs_bufsize0 = ffs->ffsbsize_b; if ((fs->ftype == TSK_FS_TYPE_FFS1) - || (fs->ftype == TSK_FS_TYPE_FFS1B)) - fs_bufsize1 = sizeof(TSK_DADDR_T) * ffs->ffsbsize_b / 4; - else - fs_bufsize1 = sizeof(TSK_DADDR_T) * ffs->ffsbsize_b / 8; + || (fs->ftype == TSK_FS_TYPE_FFS1B)) { + ptrsperblock = fs_bufsize0 / 4; + } + else { + ptrsperblock = fs_bufsize0 / 8; + } } else { fs_bufsize0 = fs->block_size; - fs_bufsize1 = sizeof(TSK_DADDR_T) * fs->block_size / 4; + ptrsperblock = fs_bufsize0 / 4; } + fs_bufsize1 = sizeof(TSK_DADDR_T) * ptrsperblock; /* * Initialize a buffer for the 3 levels of indirection that are supported by @@ -339,6 +365,42 @@ tsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file) return 1; } + if ((fs_attr_indir = + tsk_fs_attrlist_getnew(fs_meta->attr, + TSK_FS_ATTR_NONRES)) == NULL) { + free(buf); + return 1; + } + + // determine number of indirect lbocks needed for file size... + numBlocks = ((fs_meta->size + fs_bufsize0 - 1) / fs_bufsize0) - 12; + numSingIndirect = (numBlocks + ptrsperblock - 1) / ptrsperblock; + numDblIndirect = 0; + numTripIndirect = 0; + + // double block pointer? + if (numSingIndirect > 1) { + numDblIndirect = + (numSingIndirect - 1 + ptrsperblock - 1) / ptrsperblock; + if (numDblIndirect > 1) { + numTripIndirect = + (numDblIndirect - 1 + ptrsperblock - 1) / ptrsperblock; + } + } + + // initialize the data run + if (tsk_fs_attr_set_run(fs_file, fs_attr_indir, NULL, NULL, + TSK_FS_ATTR_TYPE_UNIX_INDIR, TSK_FS_ATTR_ID_DEFAULT, + fs_bufsize0 * (numSingIndirect + numDblIndirect + + numTripIndirect), + fs_bufsize0 * (numSingIndirect + numDblIndirect + + numTripIndirect), + fs_bufsize0 * (numSingIndirect + numDblIndirect + + numTripIndirect), 0, 0)) { + free(buf); + return 1; + } + for (level = 1; length > 0 && level < 4; level++) { TSK_DADDR_T *addr_ptr = (TSK_DADDR_T *) fs_meta->content_ptr; @@ -353,8 +415,8 @@ tsk_fs_unix_make_data_run(TSK_FS_FILE * fs_file) /* the indirect addresses are stored in addr_ptr after the 12 * direct addresses */ read_b = - unix_make_data_run_indirect(fs, fs_attr, buf, level, - addr_ptr[12 + level - 1], length); + unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir, + buf, level, addr_ptr[12 + level - 1], length); if (read_b == -1) break; length -= read_b;