A crafted EROFS image with circular directory references can cause dump.erofs to enter infinite recursion during statistics gathering, leading to a stack overflow.
Add a dirstack similar to fsck.erofs to track visited directory nids during traversal. Before entering a subdirectory, check that the maximum depth has not been exceeded and that the directory nid has not already been visited. This addresses the XXXX comment that was already present in the code. Signed-off-by: Utkal Singh <[email protected]> --- dump/main.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/dump/main.c b/dump/main.c index 567cff6..83b2809 100644 --- a/dump/main.c +++ b/dump/main.c @@ -72,6 +72,11 @@ struct erofs_statistics { }; static struct erofs_statistics stats; +static struct { + erofs_nid_t dirs[PATH_MAX]; + int top; +} dump_dirstack; + static struct option long_options[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, @@ -359,7 +364,6 @@ static int erofsdump_readdir(struct erofs_dir_context *ctx) update_file_size_statistics(occupied_size, false); } - /* XXXX: the dir depth should be restricted in order to avoid loops */ if (S_ISDIR(vi.i_mode)) { struct erofs_dir_context nctx = { .flags = ctx->dir ? EROFS_READDIR_VALID_PNID : 0, @@ -367,8 +371,17 @@ static int erofsdump_readdir(struct erofs_dir_context *ctx) .dir = &vi, .cb = erofsdump_dirent_iter, }; - - return erofs_iterate_dir(&nctx, false); + int i; + + if (dump_dirstack.top >= ARRAY_SIZE(dump_dirstack.dirs)) + return -ENAMETOOLONG; + for (i = 0; i < dump_dirstack.top; ++i) + if (vi.nid == dump_dirstack.dirs[i]) + return -ELOOP; + dump_dirstack.dirs[dump_dirstack.top++] = vi.nid; + err = erofs_iterate_dir(&nctx, false); + --dump_dirstack.top; + return err; } return 0; } -- 2.43.0
