From 405e90bf0df3ea238f32236f38cd302e2d4ae4f1 Mon Sep 17 00:00:00 2001 From: Brian Carrier <carrier@sleuthkit.org> Date: Sat, 31 Jul 2021 10:26:34 -0400 Subject: [PATCH] renamed from #2349 and added comments to clarify different recursion checks --- tsk/fs/fatxxfs_dent.c | 2 +- tsk/fs/fs_dir.c | 67 ++++++++++++++++++++++++------------------- tsk/fs/tsk_fs_i.h | 3 ++ 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/tsk/fs/fatxxfs_dent.c b/tsk/fs/fatxxfs_dent.c index 1354b5e8d..ad191bafa 100755 --- a/tsk/fs/fatxxfs_dent.c +++ b/tsk/fs/fatxxfs_dent.c @@ -371,7 +371,7 @@ 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_internal_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), diff --git a/tsk/fs/fs_dir.c b/tsk/fs/fs_dir.c index f08dd1715..873994712 100644 --- a/tsk/fs/fs_dir.c +++ b/tsk/fs/fs_dir.c @@ -267,16 +267,16 @@ tsk_fs_dir_add(TSK_FS_DIR * a_fs_dir, const TSK_FS_NAME * a_fs_name) /** \internal -* Internal version of the tsk_fs_dir_open_meta function with recursion depth +* 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 recursion_depth Recursion depth to limit the number of self-calls +* @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_internal(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, int recursion_depth) +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; @@ -289,7 +289,7 @@ tsk_fs_dir_open_meta_internal(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, int recursi return NULL; } - retval = a_fs->dir_open_meta(a_fs, &fs_dir, a_addr, recursion_depth); + 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; @@ -504,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_internal + * used to keep state between calls to dir_walk_recurse */ typedef struct { /* Recursive path stuff */ @@ -628,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_internal(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, int recursion_depth) + TSK_FS_DIR_WALK_CB a_action, void *a_ptr, int macro_recursion_depth) { TSK_FS_DIR *fs_dir; TSK_FS_FILE *fs_file; @@ -640,7 +640,7 @@ tsk_fs_dir_walk_internal(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_internal(a_fs, a_addr, recursion_depth + 1)) == NULL) { + if ((fs_dir = tsk_fs_dir_open_meta_internal(a_fs, a_addr, macro_recursion_depth + 1)) == NULL) { return TSK_WALK_ERROR; } @@ -797,14 +797,21 @@ tsk_fs_dir_walk_internal(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_internal: directory : %" + "tsk_fs_dir_walk_recursive: directory : %" PRIuINUM " exceeded max length / depth\n", fs_file->name->meta_addr); } @@ -835,15 +842,15 @@ tsk_fs_dir_walk_internal(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_internal(a_fs, + retval = tsk_fs_dir_walk_recursive(a_fs, a_dinfo, fs_file->name->meta_addr, a_flags, - a_action, a_ptr, recursion_depth + 1); + 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_internal: error reading directory: %" + "tsk_fs_dir_walk_recursive: error reading directory: %" PRIuINUM "\n", fs_file->name->meta_addr); tsk_error_print(stderr); } @@ -875,7 +882,7 @@ tsk_fs_dir_walk_internal(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, else { if (tsk_verbose) fprintf(stderr, - "tsk_fs_dir_walk_internal: Loop detected with address %" + "tsk_fs_dir_walk_recursive: Loop detected with address %" PRIuINUM, fs_file->name->meta_addr); } } @@ -902,20 +909,22 @@ tsk_fs_dir_walk_internal(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, /** \internal -* Internal version of the tsk_fs_dir_walk function with recursion depth +* 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 recursion_depth Recursion depth to limit the number of self-calls +* @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_internal_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, int recursion_depth) + void *a_ptr, int macro_recursion_depth) { DENT_DINFO dinfo; TSK_WALK_RET_ENUM retval; @@ -923,17 +932,17 @@ tsk_fs_dir_internal_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_internal_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 - if (recursion_depth > 128) { + // 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_internal_walk: recursion depth exceeds maximum (%d)", recursion_depth); + ("tsk_fs_dir_walk_internal: recursion depth exceeds maximum (%d)", macro_recursion_depth); return 1; } @@ -959,8 +968,8 @@ tsk_fs_dir_internal_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_internal(a_fs, &dinfo, a_addr, a_flags, - a_action, a_ptr, recursion_depth); + 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 @@ -1001,7 +1010,7 @@ 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_internal_walk(a_fs, a_addr, a_flags, a_action, a_ptr, 0); + return tsk_fs_dir_walk_internal(a_fs, a_addr, a_flags, a_action, a_ptr, 0); } /** \internal @@ -1126,7 +1135,7 @@ 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_internal_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, 0)) { tsk_error_errstr2_concat @@ -1268,7 +1277,7 @@ 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_internal_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, 0)) { diff --git a/tsk/fs/tsk_fs_i.h b/tsk/fs/tsk_fs_i.h index 17d029251..e0298f93e 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); -- GitLab