diff --git a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java index d932f948347f30fa8c6b847408af925096b14a3b..5eb37f099cffd20947e10472e32e68d9726c48d9 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java +++ b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java @@ -386,7 +386,10 @@ private long addBatchedFilesToDb() { // Currently we expect only NTFS systems to provide a windows style SID as owner id. OsAccountManager accountMgr = caseDb.getOsAccountManager(); OsAccount newAccount = accountMgr.newWindowsOsAccount(ownerUid, null, null, imageHost, OsAccountRealm.RealmScope.UNKNOWN); - accountMgr.newOsAccountInstance(newAccount.getId(), fileInfo.dataSourceObjId, OsAccountInstance.OsAccountInstanceType.ACCESSED, caseDb.getConnection()); + Content ds = caseDb.getContentById(fileInfo.dataSourceObjId); // Data sources are cached so this will only access the database once + if (ds instanceof DataSource) { + accountMgr.newOsAccountInstance(newAccount, (DataSource)ds, OsAccountInstance.OsAccountInstanceType.ACCESSED); + } ownerIdToAccountMap.put(ownerUid, newAccount); } } catch (NotUserSIDException ex) { diff --git a/tsk/fs/apfs_compat.cpp b/tsk/fs/apfs_compat.cpp index 4afacd5cb48f97a194d4bcced74c9962425e33aa..8ba784aaefe1b0cb4a8d25f011499de9a6e70821 100755 --- a/tsk/fs/apfs_compat.cpp +++ b/tsk/fs/apfs_compat.cpp @@ -226,8 +226,8 @@ APFSFSCompat::APFSFSCompat(TSK_IMG_INFO* img_info, const TSK_POOL_INFO* pool_inf }; _fsinfo.dir_open_meta = [](TSK_FS_INFO* fs, TSK_FS_DIR** a_fs_dir, - TSK_INUM_T inode) { - return to_fs(fs).dir_open_meta(a_fs_dir, inode); + TSK_INUM_T inode, int recursion_depth) { + return to_fs(fs).dir_open_meta(a_fs_dir, inode, recursion_depth); }; _fsinfo.fscheck = [](TSK_FS_INFO*, FILE*) { @@ -478,7 +478,8 @@ uint8_t tsk_apfs_fsstat(TSK_FS_INFO* fs_info, apfs_fsstat_info* info) try { } TSK_RETVAL_ENUM APFSFSCompat::dir_open_meta(TSK_FS_DIR** a_fs_dir, - TSK_INUM_T inode_num) const + TSK_INUM_T inode_num, + int recursion_depth) const noexcept try { // Sanity checks if (a_fs_dir == NULL) { @@ -568,7 +569,7 @@ uint8_t APFSFSCompat::inode_walk(TSK_FS_INFO* fs, TSK_INUM_T start_inum, TSK_INU tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("inode_walk: end object id must be >= start object id: " - "%" PRIx32 " must be >= %" PRIx32 "", + "%" PRIuINUM " must be >= %" PRIuINUM "", end_inum, start_inum); return 1; } @@ -1430,9 +1431,6 @@ uint8_t tsk_apfs_istat(TSK_FS_FILE* fs_file, apfs_istat_info* info) try { */ TSK_FS_BLOCK_FLAG_ENUM APFSFSCompat::block_getflags(TSK_FS_INFO* fs, TSK_DADDR_T addr) { - TSK_FS_FILE *fs_file; - int result; - if (fs->img_info->itype != TSK_IMG_TYPE_POOL) { // No way to return an error return TSK_FS_BLOCK_FLAG_UNALLOC; @@ -1641,7 +1639,7 @@ uint8_t tsk_apfs_free_snapshot_list(apfs_snapshot_list* list) try { return 1; } - for (auto i = 0; i < list->num_snapshots; i++) { + for (size_t i = 0; i < list->num_snapshots; i++) { auto& snapshot = list->snapshots[i]; delete[] snapshot.name; } diff --git a/tsk/fs/apfs_compat.hpp b/tsk/fs/apfs_compat.hpp index 4c40ddf5ac47752d97c1003b57424625c0d4ed64..e724e81e23c85115331a5bd2b4dc4d3a4fd152e3 100644 --- a/tsk/fs/apfs_compat.hpp +++ b/tsk/fs/apfs_compat.hpp @@ -56,5 +56,5 @@ class APFSFSCompat : public APFSJObjTree { uint8_t decrypt_block(TSK_DADDR_T, void*) noexcept; int name_cmp(const char*, const char*) const noexcept; - TSK_RETVAL_ENUM dir_open_meta(TSK_FS_DIR**, TSK_INUM_T) const noexcept; + TSK_RETVAL_ENUM dir_open_meta(TSK_FS_DIR**, TSK_INUM_T, int) const noexcept; }; diff --git a/tsk/fs/exfatfs_dent.c b/tsk/fs/exfatfs_dent.c index 714d88a21dc1a6aa8c34a96b1452f331508be3cc..6459e4a06dc97e21dc93d6dec08f25fb16c39885 100755 --- a/tsk/fs/exfatfs_dent.c +++ b/tsk/fs/exfatfs_dent.c @@ -475,15 +475,16 @@ exfats_parse_special_file_dentry(EXFATFS_FS_NAME_INFO *a_name_info, FATFS_DENTRY * be added. * @param a_buf Buffer that contains the directory contents. * @param a_buf_len Length of buffer in bytes (must be a multiple of sector -* size). + * size). * @param a_sector_addrs Array where each element is the original address of * the corresponding sector in a_buf (size of array is number of sectors in * the directory). + * @param recursion_depth Recursion depth to limit the number of self-calls * @return TSK_RETVAL_ENUM */ TSK_RETVAL_ENUM exfatfs_dent_parse_buf(FATFS_INFO *a_fatfs, TSK_FS_DIR *a_fs_dir, char *a_buf, - TSK_OFF_T a_buf_len, TSK_DADDR_T *a_sector_addrs) + TSK_OFF_T a_buf_len, TSK_DADDR_T *a_sector_addrs, int recursion_depth) { const char *func_name = "exfatfs_parse_directory_buf"; TSK_FS_INFO *fs = NULL; diff --git a/tsk/fs/ext2fs.c b/tsk/fs/ext2fs.c index 29bed30ce79d2e726a1a21de0e64a613ab6dbb65..546db8cbf80e4a99b2645957727ca9541e2b0624 100755 --- a/tsk/fs/ext2fs.c +++ b/tsk/fs/ext2fs.c @@ -635,7 +635,7 @@ ext4_load_attrs_inline(TSK_FS_FILE *fs_file, const uint8_t * ea_buf, size_t ea_b // This is the right attribute. Check that the length and offset are valid. // The offset is from the beginning of the entries, i.e., four bytes into the buffer. - uint32_t offset = tsk_getu32(fs_file->fs_info->endian, ea_entry->val_off); + uint16_t offset = tsk_getu16(fs_file->fs_info->endian, ea_entry->val_off); uint32_t size = tsk_getu32(fs_file->fs_info->endian, ea_entry->val_size); if (4 + offset + size <= ea_buf_len) { ea_inline_data = &(ea_buf[4 + offset]); @@ -1665,7 +1665,7 @@ ext2fs_make_data_run_extent_index(TSK_FS_INFO * fs_info, // Ensure buf is sufficiently large // Otherwise extents[i] below can cause an OOB read - if ((fs_blocksize < sizeof(ext2fs_extent_header)) || (num_entries > (fs_blocksize - sizeof(ext2fs_extent_header)) / sizeof(ext2fs_extent))) { + if (((unsigned long)fs_blocksize < sizeof(ext2fs_extent_header)) || (num_entries > (fs_blocksize - sizeof(ext2fs_extent_header)) / sizeof(ext2fs_extent))) { free(buf); return 1; } @@ -1684,7 +1684,7 @@ ext2fs_make_data_run_extent_index(TSK_FS_INFO * fs_info, // Ensure buf is sufficiently large // Otherwise indices[i] below can cause an OOB read - if ((fs_blocksize < sizeof(ext2fs_extent_header)) || (num_entries > (fs_blocksize - sizeof(ext2fs_extent_header)) / sizeof(ext2fs_extent_idx))) { + if (((unsigned long)fs_blocksize < sizeof(ext2fs_extent_header)) || (num_entries > (fs_blocksize - sizeof(ext2fs_extent_header)) / sizeof(ext2fs_extent_idx))) { free(buf); return 1; } @@ -1715,7 +1715,7 @@ ext2fs_make_data_run_extent_index(TSK_FS_INFO * fs_info, */ static int32_t ext2fs_extent_tree_index_count(TSK_FS_INFO * fs_info, - TSK_FS_META * fs_meta, ext2fs_extent_header * header) + TSK_FS_META * fs_meta, ext2fs_extent_header * header, int recursion_depth) { int fs_blocksize = fs_info->block_size; ext2fs_extent_idx *indices; @@ -1723,6 +1723,13 @@ ext2fs_extent_tree_index_count(TSK_FS_INFO * fs_info, uint8_t *buf; int i; + // 32 is an arbitrary chosen value. + if (recursion_depth > 32) { + tsk_error_set_errno(TSK_ERR_FS_INODE_COR); + tsk_error_set_errstr + ("ext2fs_load_attrs: exceeded maximum recursion depth!"); + return -1; + } if (tsk_getu16(fs_info->endian, header->eh_magic) != 0xF30A) { tsk_error_set_errno(TSK_ERR_FS_INODE_COR); tsk_error_set_errstr @@ -1761,7 +1768,7 @@ ext2fs_extent_tree_index_count(TSK_FS_INFO * fs_info, if ((ret = ext2fs_extent_tree_index_count(fs_info, fs_meta, - (ext2fs_extent_header *) buf)) < 0) { + (ext2fs_extent_header *) buf, recursion_depth + 1)) < 0) { return -1; } count += ret; @@ -1936,7 +1943,7 @@ ext4_load_attrs_extents(TSK_FS_FILE *fs_file) } extent_index_size = - ext2fs_extent_tree_index_count(fs_info, fs_meta, header); + ext2fs_extent_tree_index_count(fs_info, fs_meta, header, 0); if (extent_index_size < 0) { return 1; } diff --git a/tsk/fs/ext2fs_dent.c b/tsk/fs/ext2fs_dent.c index 95e8b256961bdd504dcc91b34a2d4abeb2140e30..8fa140a8f3046d0d85b0038b3f02409a61ac2b80 100644 --- a/tsk/fs/ext2fs_dent.c +++ b/tsk/fs/ext2fs_dent.c @@ -232,12 +232,13 @@ ext2fs_dent_parse_block(EXT2FS_INFO * ext2fs, TSK_FS_DIR * a_fs_dir, * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. +* @param recursion_depth Recursion depth to limit the number of self-calls * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM ext2fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) a_fs; char *dirbuf; diff --git a/tsk/fs/fatfs_dent.cpp b/tsk/fs/fatfs_dent.cpp index c1e86f0558e4caa8d8151adec8682b26e8cf22c4..93d80bca90961b31f93b25bc165c32a759ba7843 100644 --- a/tsk/fs/fatfs_dent.cpp +++ b/tsk/fs/fatfs_dent.cpp @@ -219,12 +219,13 @@ static TSK_WALK_RET_ENUM * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. +* @param recursion_depth Recursion depth to limit the number of self-calls * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM fatfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { const char *func_name = "fatfs_dir_open_meta"; TSK_OFF_T size, len; @@ -344,7 +345,7 @@ TSK_RETVAL_ENUM "%s: Parsing directory %" PRIuINUM "\n", func_name, a_addr); - retval = fatfs->dent_parse_buf(fatfs, fs_dir, dirbuf, len, addrbuf); + retval = fatfs->dent_parse_buf(fatfs, fs_dir, dirbuf, len, addrbuf, recursion_depth); free(dirbuf); free(addrbuf); diff --git a/tsk/fs/fatxxfs_dent.c b/tsk/fs/fatxxfs_dent.c index a68c7c6f99a7e29a52358cc3f200891a7dbfc32d..ad191bafaf3c22a651eaf81e75bd7028127073cd 100755 --- a/tsk/fs/fatxxfs_dent.c +++ b/tsk/fs/fatxxfs_dent.c @@ -48,15 +48,16 @@ typedef struct { * be added. * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector -* size). + * size). * @param addrs Array where each element is the original address of * the corresponding sector in a_buf (size of array is number of sectors in * the directory). + * @param recursion_depth Recursion depth to limit the number of self-calls * @return TSK_RETVAL_ENUM */ TSK_RETVAL_ENUM fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf, - TSK_OFF_T len, TSK_DADDR_T *addrs) + TSK_OFF_T len, TSK_DADDR_T *addrs, int recursion_depth) { char *func_name = "fatxxfs_dent_parse_buf"; unsigned int idx = 0; @@ -370,12 +371,12 @@ fatxxfs_dent_parse_buf(FATFS_INFO *fatfs, TSK_FS_DIR *a_fs_dir, char *buf, /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ - if (tsk_fs_dir_walk(fs, fs->root_inum, + if (tsk_fs_dir_walk_internal(fs, fs->root_inum, (TSK_FS_DIR_WALK_FLAG_ENUM)(TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE), fatfs_find_parent_act, - (void *) &a_fs_dir->fs_file->meta->addr)) { + (void *) &a_fs_dir->fs_file->meta->addr, recursion_depth)) { return TSK_OK; } diff --git a/tsk/fs/ffs_dent.c b/tsk/fs/ffs_dent.c index a9e9aec334c72fb7343acb4c2bd7d2f6c83cd984..7a032ccda70e6074554e014a52f5efb9682b5561 100644 --- a/tsk/fs/ffs_dent.c +++ b/tsk/fs/ffs_dent.c @@ -222,11 +222,12 @@ ffs_dent_parse_block(FFS_INFO * ffs, TSK_FS_DIR * fs_dir, uint8_t a_is_del, * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. + * @param recursion_depth Recursion depth to limit the number of self-calls * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM ffs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { TSK_OFF_T size; FFS_INFO *ffs = (FFS_INFO *) a_fs; diff --git a/tsk/fs/fs_dir.c b/tsk/fs/fs_dir.c index b80c0012fbaa0895f28c27fe24c01ef5f76d2db5..873994712636d436572cd780dc27739fef5a8f24 100644 --- a/tsk/fs/fs_dir.c +++ b/tsk/fs/fs_dir.c @@ -266,14 +266,17 @@ tsk_fs_dir_add(TSK_FS_DIR * a_fs_dir, const TSK_FS_NAME * a_fs_name) -/** \ingroup fslib +/** \internal +* Internal version of the tsk_fs_dir_open_meta function with macro recursion depth. +* * Open a directory (using its metadata addr) so that each of the files in it can be accessed. * @param a_fs File system to analyze * @param a_addr Metadata address of the directory to open +* @param macro_recursion_depth Recursion depth to limit the number of calls if the underlying file system needs to call methods to resolve. * @returns NULL on error */ -TSK_FS_DIR * -tsk_fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr) +static TSK_FS_DIR * +tsk_fs_dir_open_meta_internal(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, int macro_recursion_depth) { TSK_FS_DIR *fs_dir = NULL; TSK_RETVAL_ENUM retval; @@ -282,11 +285,11 @@ tsk_fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr) || (a_fs->dir_open_meta == NULL)) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr - ("tsk_fs_dir_open_meta: called with NULL or unallocated structures"); + ("tsk_fs_dir_open_meta_internal: called with NULL or unallocated structures"); return NULL; } - retval = a_fs->dir_open_meta(a_fs, &fs_dir, a_addr); + retval = a_fs->dir_open_meta(a_fs, &fs_dir, a_addr, macro_recursion_depth); if (retval != TSK_OK) { tsk_fs_dir_close(fs_dir); return NULL; @@ -296,6 +299,21 @@ tsk_fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr) } + +/** \ingroup fslib +* Open a directory (using its metadata addr) so that each of the files in it can be accessed. +* +* @param a_fs File system to analyze +* @param a_addr Metadata address of the directory to open +* @returns NULL on error +*/ +TSK_FS_DIR * +tsk_fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr) +{ + return tsk_fs_dir_open_meta_internal(a_fs, a_addr, 0); +} + + /** \ingroup fslib * Open a directory (using its path) so that each of the files in it can be accessed. * @param a_fs File system to analyze @@ -486,7 +504,7 @@ tsk_fs_dir_get_name(const TSK_FS_DIR * a_fs_dir, size_t a_idx) #define DIR_STRSZ 4096 /** \internal - * used to keep state between calls to dir_walk_lcl + * used to keep state between calls to dir_walk_recurse */ typedef struct { /* Recursive path stuff */ @@ -610,11 +628,11 @@ prioritizeDirNames(TSK_FS_NAME * names, size_t count, int * indexToOrderedIndex) } /* dir_walk local function that is used for recursive calls. Callers - * should initially call the non-local version. */ + * should initially call the non-recursive version. */ static TSK_WALK_RET_ENUM -tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, +tsk_fs_dir_walk_recursive(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags, - TSK_FS_DIR_WALK_CB a_action, void *a_ptr) + TSK_FS_DIR_WALK_CB a_action, void *a_ptr, int macro_recursion_depth) { TSK_FS_DIR *fs_dir; TSK_FS_FILE *fs_file; @@ -622,7 +640,7 @@ tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, int* indexToOrderedIndex = NULL; // get the list of entries in the directory - if ((fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr)) == NULL) { + if ((fs_dir = tsk_fs_dir_open_meta_internal(a_fs, a_addr, macro_recursion_depth + 1)) == NULL) { return TSK_WALK_ERROR; } @@ -779,14 +797,21 @@ tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, } /* If we've exceeded the max depth or max length, don't - * recurse any further into this directory */ + * recurse any further into this directory + * NOTE: We have two concepts of recursion detection in + * here. This one is based on within a top-level call + * to dir_walk. The macro_recursion_depth value allows + * us to detect when file systems need to call dir_walk + * to resolve things and they get into an infinite loop. + * Perhaps they can be unified some day. + */ if ((a_dinfo->depth >= MAX_DEPTH) || (DIR_STRSZ <= strlen(a_dinfo->dirs) + strlen(fs_file->name->name))) { if (tsk_verbose) { tsk_fprintf(stdout, - "tsk_fs_dir_walk_lcl: directory : %" + "tsk_fs_dir_walk_recursive: directory : %" PRIuINUM " exceeded max length / depth\n", fs_file->name->meta_addr); } @@ -817,15 +842,15 @@ tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, save_bak = a_dinfo->save_inum_named; a_dinfo->save_inum_named = 0; } - retval = tsk_fs_dir_walk_lcl(a_fs, + retval = tsk_fs_dir_walk_recursive(a_fs, a_dinfo, fs_file->name->meta_addr, a_flags, - a_action, a_ptr); + a_action, a_ptr, macro_recursion_depth + 1); if (retval == TSK_WALK_ERROR) { /* If this fails because the directory could not be * loaded, then we still continue */ if (tsk_verbose) { tsk_fprintf(stderr, - "tsk_fs_dir_walk_lcl: error reading directory: %" + "tsk_fs_dir_walk_recursive: error reading directory: %" PRIuINUM "\n", fs_file->name->meta_addr); tsk_error_print(stderr); } @@ -857,7 +882,7 @@ tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, else { if (tsk_verbose) fprintf(stderr, - "tsk_fs_dir_walk_lcl: Loop detected with address %" + "tsk_fs_dir_walk_recursive: Loop detected with address %" PRIuINUM, fs_file->name->meta_addr); } } @@ -883,20 +908,23 @@ tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, } -/** \ingroup fslib -* Walk the file names in a directory and obtain the details of the files via a callback. +/** \internal +* Internal version of the tsk_fs_dir_walk function with recursion depth. +* This should be called by file systems when they need to start a new dir_walk +* to resolve something and they may already be inside of a walk. * * @param a_fs File system to analyze * @param a_addr Metadata address of the directory to analyze * @param a_flags Flags used during analysis * @param a_action Callback function that is called for each file name * @param a_ptr Pointer to data that is passed to the callback function each time +* @param macro_recursion_depth Recursion depth to limit the number of self-calls in case the underlying file system also needs to make calls into dir_walk * @returns 1 on error and 0 on success */ uint8_t -tsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, +tsk_fs_dir_walk_internal(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, - void *a_ptr) + void *a_ptr, int macro_recursion_depth) { DENT_DINFO dinfo; TSK_WALK_RET_ENUM retval; @@ -904,7 +932,17 @@ tsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr - ("tsk_fs_dir_walk: called with NULL or unallocated structures"); + ("tsk_fs_dir_walk_internal: called with NULL or unallocated structures"); + return 1; + } + + // 128 is a somewhat arbitrary value. + // https://github.com/sleuthkit/sleuthkit/issues/1859 identified + // an overflow with 240 levels of recursion with FAT + if (macro_recursion_depth > 128) { + tsk_error_set_errno(TSK_ERR_FS_ARG); + tsk_error_set_errstr + ("tsk_fs_dir_walk_internal: recursion depth exceeds maximum (%d)", macro_recursion_depth); return 1; } @@ -930,8 +968,8 @@ tsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, } tsk_release_lock(&a_fs->list_inum_named_lock); - retval = tsk_fs_dir_walk_lcl(a_fs, &dinfo, a_addr, a_flags, - a_action, a_ptr); + retval = tsk_fs_dir_walk_recursive(a_fs, &dinfo, a_addr, a_flags, + a_action, a_ptr, macro_recursion_depth); // if we were saving the list of named files in the temp list, // then now save them to FS_INFO @@ -957,6 +995,24 @@ tsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, } +/** \ingroup fslib +* Walk the file names in a directory and obtain the details of the files via a callback. +* +* @param a_fs File system to analyze +* @param a_addr Metadata address of the directory to analyze +* @param a_flags Flags used during analysis +* @param a_action Callback function that is called for each file name +* @param a_ptr Pointer to data that is passed to the callback function each time +* @returns 1 on error and 0 on success +*/ +uint8_t +tsk_fs_dir_walk(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, + TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, + void *a_ptr) +{ + return tsk_fs_dir_walk_internal(a_fs, a_addr, a_flags, a_action, a_ptr, 0); +} + /** \internal * Create a dummy NAME entry for the Orphan file virtual directory. * @param a_fs File system directory is for @@ -1079,9 +1135,9 @@ tsk_fs_dir_load_inum_named(TSK_FS_INFO * a_fs) * specify UNALLOC only as a flag on the assumption that there will * be fewer callbacks for UNALLOC than ALLOC. */ - if (tsk_fs_dir_walk(a_fs, a_fs->root_inum, + if (tsk_fs_dir_walk_internal(a_fs, a_fs->root_inum, TSK_FS_NAME_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE | - TSK_FS_DIR_WALK_FLAG_NOORPHAN, load_named_dir_walk_cb, NULL)) { + TSK_FS_DIR_WALK_FLAG_NOORPHAN, load_named_dir_walk_cb, NULL, 0)) { tsk_error_errstr2_concat ("- tsk_fs_dir_load_inum_named: identifying inodes allocated by file names"); return TSK_ERR; @@ -1221,10 +1277,10 @@ find_orphan_meta_walk_cb(TSK_FS_FILE * a_fs_file, void *a_ptr) "find_orphan_meta_walk_cb: Going into directory %" PRIuINUM " to mark contents as seen\n", a_fs_file->meta->addr); - if (tsk_fs_dir_walk(fs, a_fs_file->meta->addr, + if (tsk_fs_dir_walk_internal(fs, a_fs_file->meta->addr, TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN, load_orphan_dir_walk_cb, - data)) { + data, 0)) { tsk_error_errstr2_concat (" - find_orphan_meta_walk_cb: identifying inodes allocated by file names"); return TSK_WALK_ERROR; diff --git a/tsk/fs/fs_open.c b/tsk/fs/fs_open.c index c3e96e4e3a2a6a2f2af63310f834b01da4320b52..dc5eed72d52a01ec3a4edbe63b391f2b43eee7be 100644 --- a/tsk/fs/fs_open.c +++ b/tsk/fs/fs_open.c @@ -206,7 +206,7 @@ tsk_fs_open_img_decrypt(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset, unsupportedSignatureFound = 1; tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_UNSUPTYPE); - tsk_error_set_errstr(imageType); + tsk_error_set_errstr("%s", imageType); free(imageType); } } @@ -217,11 +217,11 @@ tsk_fs_open_img_decrypt(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset, if (result != NULL) { if (result->encryptionType == ENCRYPTION_DETECTED_SIGNATURE) { tsk_error_set_errno(TSK_ERR_FS_ENCRYPTED); - tsk_error_set_errstr(result->desc); + tsk_error_set_errstr("%s", result->desc); } else if (result->encryptionType == ENCRYPTION_DETECTED_ENTROPY) { tsk_error_set_errno(TSK_ERR_FS_POSSIBLY_ENCRYPTED); - tsk_error_set_errstr(result->desc); + tsk_error_set_errstr("%s", result->desc); } else { tsk_error_set_errno(TSK_ERR_FS_UNKTYPE); diff --git a/tsk/fs/hfs_dent.c b/tsk/fs/hfs_dent.c index 54460f14bfe078ca31ef3edf85d849ecb79af46d..0c1f97dd12333e671e32a929040c7859fe525dd7 100644 --- a/tsk/fs/hfs_dent.c +++ b/tsk/fs/hfs_dent.c @@ -384,11 +384,12 @@ hfs_dir_open_meta_cb(HFS_INFO * hfs, int8_t level_type, * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. +* @param recursion_depth Recursion depth to limit the number of self-calls * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM hfs_dir_open_meta(TSK_FS_INFO * fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { HFS_INFO *hfs = (HFS_INFO *) fs; uint32_t cnid; /* catalog node ID of the entry (= inum) */ diff --git a/tsk/fs/iso9660_dent.c b/tsk/fs/iso9660_dent.c index 34de246a422e63863ad0a0118c70e7981149740b..8765f2a33f0187652e24ce91286b723690b15de9 100644 --- a/tsk/fs/iso9660_dent.c +++ b/tsk/fs/iso9660_dent.c @@ -218,11 +218,12 @@ iso9660_proc_dir(TSK_FS_INFO * a_fs, TSK_FS_DIR * a_fs_dir, const char *buf, * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. + * @param recursion_depth Recursion depth to limit the number of self-calls * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM iso9660_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { TSK_RETVAL_ENUM retval; TSK_FS_DIR *fs_dir; diff --git a/tsk/fs/nofs_misc.c b/tsk/fs/nofs_misc.c index 0829d1a7dd879e5a5ce0538892510fd3c4151f10..5e24dc59183488e1ef43323fbe959782d76c381a 100644 --- a/tsk/fs/nofs_misc.c +++ b/tsk/fs/nofs_misc.c @@ -215,7 +215,7 @@ tsk_fs_nofs_istat(TSK_FS_INFO * a_fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * */ TSK_RETVAL_ENUM tsk_fs_nofs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNSUPFUNC); diff --git a/tsk/fs/ntfs.c b/tsk/fs/ntfs.c old mode 100755 new mode 100644 index e33306ab69d966b4290aaa4a5329b2ac42bfed77..ce46f1909a8e9cb6491c91ebbd1d2aaee9f8086a --- a/tsk/fs/ntfs.c +++ b/tsk/fs/ntfs.c @@ -379,6 +379,9 @@ ntfs_dinode_lookup(NTFS_INFO * a_ntfs, char *a_buf, TSK_INUM_T a_mftnum) uint16_t upd_off = tsk_getu16(fs->endian, mft->upd_off); // Make sure upd_cnt > 0 to prevent an integer wrap around. + // NOTE: There is a bug here because upd_cnt can be for unused entries. + // They are now skipped (as of July 2021). We shoudl refactor this code + // to allow upd_cnt = 0. if ((upd_cnt == 0) || (upd_cnt > (((a_ntfs->mft_rsize_b) / 2) + 1))) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_INODE_COR); @@ -860,6 +863,7 @@ ntfs_uncompress_setup(TSK_FS_INFO * fs, NTFS_COMP_INFO * comp, if (comp->buf_size_b < fs->block_size) { return 1; } + if ((comp->uncomp_buf = tsk_malloc(comp->buf_size_b)) == NULL) { comp->buf_size_b = 0; return 1; diff --git a/tsk/fs/ntfs_dent.cpp b/tsk/fs/ntfs_dent.cpp index 9070182fe3ec326f97ea47ed1405cbbde2f706a7..ee3b772b447af7ae0062a034c6b12e9356769d92 100644 --- a/tsk/fs/ntfs_dent.cpp +++ b/tsk/fs/ntfs_dent.cpp @@ -743,11 +743,12 @@ ntfs_fix_idxrec(NTFS_INFO * ntfs, ntfs_idxrec * idxrec, uint32_t len) * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. +* @param recursion_depth Recursion depth to limit the number of self-calls * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM ntfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { NTFS_INFO *ntfs = (NTFS_INFO *) a_fs; TSK_FS_DIR *fs_dir; diff --git a/tsk/fs/tsk_exfatfs.h b/tsk/fs/tsk_exfatfs.h index 2f88ab145c2a9b47a7f0c431c4c8888f98859b55..475672fe1f6c482ec27dfc1d5f43be5a0261bcd4 100755 --- a/tsk/fs/tsk_exfatfs.h +++ b/tsk/fs/tsk_exfatfs.h @@ -401,7 +401,7 @@ extern "C" { extern TSK_RETVAL_ENUM exfatfs_dent_parse_buf(FATFS_INFO *a_fatfs, TSK_FS_DIR *a_fs_dir, char *a_buf, - TSK_OFF_T a_buf_len, TSK_DADDR_T *a_sector_addrs); + TSK_OFF_T a_buf_len, TSK_DADDR_T *a_sector_addrs, int recursion_depth); #ifdef __cplusplus } diff --git a/tsk/fs/tsk_ext2fs.h b/tsk/fs/tsk_ext2fs.h index 71640f5fd67ffbb68815568886a7bd8263e17adc..348b6b9ae2070db67a8a78b06d24f3ae02bd8ea0 100644 --- a/tsk/fs/tsk_ext2fs.h +++ b/tsk/fs/tsk_ext2fs.h @@ -679,7 +679,7 @@ extern "C" { extern TSK_RETVAL_ENUM ext2fs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr); + TSK_INUM_T a_addr, int recursion_depth); extern uint8_t ext2fs_jentry_walk(TSK_FS_INFO *, int, TSK_FS_JENTRY_WALK_CB, void *); extern uint8_t ext2fs_jblk_walk(TSK_FS_INFO *, TSK_DADDR_T, diff --git a/tsk/fs/tsk_fatfs.h b/tsk/fs/tsk_fatfs.h index ba60294c282bdd8ee67ccf72f5545d4af756a07b..1e3133728618852d025fbe9fb02149f0d011f848 100644 --- a/tsk/fs/tsk_fatfs.h +++ b/tsk/fs/tsk_fatfs.h @@ -266,7 +266,7 @@ extern "C" { TSK_RETVAL_ENUM (*dent_parse_buf)(FATFS_INFO *a_fatfs, TSK_FS_DIR *a_fs_dir, char *a_buf, TSK_OFF_T a_buf_len, - TSK_DADDR_T *a_sector_addrs); + TSK_DADDR_T *a_sector_addrs, int recursion_depth); TSK_RETVAL_ENUM (*dinode_copy)(FATFS_INFO *a_fatfs, TSK_INUM_T a_inum, FATFS_DENTRY *a_dentry, uint8_t a_cluster_is_alloc, TSK_FS_FILE *a_fs_file); @@ -347,7 +347,7 @@ extern "C" { extern TSK_RETVAL_ENUM fatfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr); + TSK_INUM_T a_addr, int recursion_depth); extern int fatfs_name_cmp(TSK_FS_INFO *, const char *, const char *); diff --git a/tsk/fs/tsk_fatxxfs.h b/tsk/fs/tsk_fatxxfs.h index e315a244811f02ebd9f2c921e6df97d87883eecc..919458e74d095357102c5f250784810b97a3ca4f 100755 --- a/tsk/fs/tsk_fatxxfs.h +++ b/tsk/fs/tsk_fatxxfs.h @@ -195,7 +195,7 @@ extern "C" { extern TSK_RETVAL_ENUM fatxxfs_dent_parse_buf(FATFS_INFO * fatfs, TSK_FS_DIR * a_fs_dir, char *buf, - TSK_OFF_T len, TSK_DADDR_T * addrs); + TSK_OFF_T len, TSK_DADDR_T * addrs, int recursion_depth); #ifdef __cplusplus } diff --git a/tsk/fs/tsk_ffs.h b/tsk/fs/tsk_ffs.h index 08f55341506142248d1700b0bb5b809d56795212..0255b5c91e461c2772f949798c7251092b192164 100644 --- a/tsk/fs/tsk_ffs.h +++ b/tsk/fs/tsk_ffs.h @@ -498,7 +498,7 @@ extern "C" { } FFS_INFO; extern TSK_RETVAL_ENUM ffs_dir_open_meta(TSK_FS_INFO * a_fs, - TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr); + TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr, int recursion_depth); #ifdef __cplusplus } diff --git a/tsk/fs/tsk_fs.h b/tsk/fs/tsk_fs.h index d0b5d1dc59697222a59fc889a8e3de8248a17e45..dca96c0b5b6182cd6c4bb6438c8f4dc0265485d8 100644 --- a/tsk/fs/tsk_fs.h +++ b/tsk/fs/tsk_fs.h @@ -1016,7 +1016,7 @@ extern "C" { uint8_t(*istat) (TSK_FS_INFO * fs, TSK_FS_ISTAT_FLAG_ENUM flags, FILE * hFile, TSK_INUM_T inum, TSK_DADDR_T numblock, int32_t sec_skew); - TSK_RETVAL_ENUM(*dir_open_meta) (TSK_FS_INFO * fs, TSK_FS_DIR ** a_fs_dir, TSK_INUM_T inode); ///< \internal Call tsk_fs_dir_open_meta() instead. + TSK_RETVAL_ENUM(*dir_open_meta) (TSK_FS_INFO * fs, TSK_FS_DIR ** a_fs_dir, TSK_INUM_T inode, int recursion_depth); ///< \internal Call tsk_fs_dir_open_meta() instead. uint8_t(*jopen) (TSK_FS_INFO *, TSK_INUM_T); ///< \internal diff --git a/tsk/fs/tsk_fs_i.h b/tsk/fs/tsk_fs_i.h index 0340e82acf2e602e8b2929acab4ac8cd5ceada27..e0298f93eef17397a7d089cee684aed95e53bf53 100644 --- a/tsk/fs/tsk_fs_i.h +++ b/tsk/fs/tsk_fs_i.h @@ -141,6 +141,9 @@ extern "C" { extern void tsk_fs_dir_reset(TSK_FS_DIR * a_fs_dir); extern uint8_t tsk_fs_dir_contains(TSK_FS_DIR * a_fs_dir, TSK_INUM_T meta_addr, uint32_t hash); extern uint32_t tsk_fs_dir_hash(const char *str); + extern uint8_t tsk_fs_dir_walk_internal(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, + TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, + void *a_ptr, int macro_recursion_depth); /* Orphan Directory Support */ TSK_RETVAL_ENUM tsk_fs_dir_load_inum_named(TSK_FS_INFO * a_fs); @@ -228,7 +231,7 @@ extern "C" { extern uint8_t tsk_fs_nofs_istat(TSK_FS_INFO * a_fs, TSK_FS_ISTAT_FLAG_ENUM istat_flags, FILE * hFile, TSK_INUM_T inum, TSK_DADDR_T numblock, int32_t sec_skew); extern TSK_RETVAL_ENUM tsk_fs_nofs_dir_open_meta(TSK_FS_INFO * a_fs, - TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr); + TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr, int recursion_depth); extern uint8_t tsk_fs_nofs_jopen(TSK_FS_INFO * a_fs, TSK_INUM_T inum); extern uint8_t tsk_fs_nofs_jentry_walk(TSK_FS_INFO * a_fs, int a_flags, TSK_FS_JENTRY_WALK_CB a_action, void *a_ptr); diff --git a/tsk/fs/tsk_hfs.h b/tsk/fs/tsk_hfs.h index 2530e0cfe324680852dd25d011cc5bbb49eb03c5..93323518ac1ac148ffab1297902943bd538c06bd 100644 --- a/tsk/fs/tsk_hfs.h +++ b/tsk/fs/tsk_hfs.h @@ -740,7 +740,7 @@ extern uint16_t hfs_get_idxkeylen(HFS_INFO * hfs, uint16_t keylen, extern TSK_RETVAL_ENUM hfs_dir_open_meta(TSK_FS_INFO *, TSK_FS_DIR **, - TSK_INUM_T); + TSK_INUM_T, int); extern int hfs_name_cmp(TSK_FS_INFO *, const char *, const char *); extern uint8_t hfs_jopen(TSK_FS_INFO *, TSK_INUM_T); diff --git a/tsk/fs/tsk_iso9660.h b/tsk/fs/tsk_iso9660.h index c822d1847d454214bdd00a73fefe4a0b51438153..7deaa97272dba803d9b774ae9ef3eaae6bbd99dd 100644 --- a/tsk/fs/tsk_iso9660.h +++ b/tsk/fs/tsk_iso9660.h @@ -392,7 +392,7 @@ typedef struct { } ISO_INFO; extern TSK_RETVAL_ENUM iso9660_dir_open_meta(TSK_FS_INFO * a_fs, - TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr); + TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr, int recursion_depth); extern uint8_t iso9660_dinode_load(ISO_INFO * iso, TSK_INUM_T inum, iso9660_inode * dinode); diff --git a/tsk/fs/tsk_ntfs.h b/tsk/fs/tsk_ntfs.h index 6364dc8bf219ed99612d5d17f0db098bc0424e74..c16696a75c5209341872913297f7910e035ace3b 100644 --- a/tsk/fs/tsk_ntfs.h +++ b/tsk/fs/tsk_ntfs.h @@ -750,7 +750,7 @@ extern "C" { extern TSK_RETVAL_ENUM ntfs_dinode_lookup(NTFS_INFO *, char *, TSK_INUM_T); extern TSK_RETVAL_ENUM ntfs_dir_open_meta(TSK_FS_INFO * a_fs, - TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr); + TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr, int recursion_depth); extern void ntfs_orphan_map_free(NTFS_INFO * a_ntfs); diff --git a/tsk/fs/yaffs.cpp b/tsk/fs/yaffs.cpp index 620f38e70410303c6a9d840b7e556e70322613fa..b8798126ae76bde351e734461cf486c037cecfc0 100755 --- a/tsk/fs/yaffs.cpp +++ b/tsk/fs/yaffs.cpp @@ -2686,7 +2686,7 @@ static TSK_RETVAL_ENUM static TSK_RETVAL_ENUM yaffsfs_dir_open_meta(TSK_FS_INFO *a_fs, TSK_FS_DIR ** a_fs_dir, - TSK_INUM_T a_addr) + TSK_INUM_T a_addr, int recursion_depth) { TSK_FS_DIR *fs_dir; TSK_FS_NAME *fs_name; diff --git a/tsk/util/detect_encryption.c b/tsk/util/detect_encryption.c index 9e64cbcaac5996059ec05c7eb0a4dc18261d3e62..f50db1549da8f3eff0cb283fdd60b72008e2ca72 100644 --- a/tsk/util/detect_encryption.c +++ b/tsk/util/detect_encryption.c @@ -121,11 +121,11 @@ calculateEntropy(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) { break; } - if (tsk_img_read(img_info, offset + i * bufLen, buf, bufLen) != bufLen) { + if (tsk_img_read(img_info, offset + i * bufLen, buf, bufLen) != (ssize_t) bufLen) { break; } - for (int j = 0; j < bufLen; j++) { + for (size_t j = 0; j < bufLen; j++) { unsigned char b = buf[j] & 0xff; byteCounts[b]++; } @@ -176,7 +176,7 @@ detectVolumeEncryption(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) { if (buf == NULL) { return result; } - if (tsk_img_read(img_info, offset, buf, len) != len) { + if (tsk_img_read(img_info, offset, buf, len) != (ssize_t)len) { free(buf); return result; } @@ -250,7 +250,7 @@ detectDiskEncryption(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) { if (buf == NULL) { return result; } - if (tsk_img_read(img_info, offset, buf, len) != len) { + if (tsk_img_read(img_info, offset, buf, len) != (ssize_t)len) { free(buf); return result; } diff --git a/tsk/vs/mm_open.c b/tsk/vs/mm_open.c index 6ac5a6ce8daf774fe24128ea6e9173ab9916fb83..ca1a413db66439100b16be15df08b8f4a3610ed6 100644 --- a/tsk/vs/mm_open.c +++ b/tsk/vs/mm_open.c @@ -184,7 +184,7 @@ tsk_vs_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset, if (result != NULL) { if (result->encryptionType == ENCRYPTION_DETECTED_SIGNATURE) { tsk_error_set_errno(TSK_ERR_VS_ENCRYPTED); - tsk_error_set_errstr(result->desc); + tsk_error_set_errstr("%s", result->desc); } free(result); result = NULL;