[PATCH] erofs-utils: fsck: fix stack-overflow due to directory loops
Gao Xiang
hsiangkao at linux.alibaba.com
Thu Feb 27 13:56:39 AEDT 2025
Just record all parent directories to address this issue as
a trivial solution for now.
Closes: https://github.com/erofs/erofs-utils/issues/15
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
fsck/main.c | 17 +++++++++++++++--
lib/dir.c | 2 +-
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/fsck/main.c b/fsck/main.c
index 372fee6..0e8b944 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -20,7 +20,13 @@
static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid);
+struct erofsfsck_dirstack {
+ erofs_nid_t dirs[PATH_MAX];
+ int top;
+};
+
struct erofsfsck_cfg {
+ struct erofsfsck_dirstack dirstack;
u64 physical_blocks;
u64 logical_blocks;
char *extract_path;
@@ -967,7 +973,7 @@ verify:
static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
{
- int ret;
+ int ret, i;
struct erofs_inode inode;
erofs_dbg("check inode: nid(%llu)", nid | 0ULL);
@@ -999,7 +1005,6 @@ static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
return ret;
}
- /* XXXX: the dir depth should be restricted in order to avoid loops */
if (S_ISDIR(inode.i_mode)) {
struct erofs_dir_context ctx = {
.flags = EROFS_READDIR_VALID_PNID,
@@ -1008,7 +1013,15 @@ static int erofsfsck_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
.cb = erofsfsck_dirent_iter,
};
+ /* XXX: support the deeper cases later */
+ if (fsckcfg.dirstack.top >= ARRAY_SIZE(fsckcfg.dirstack.dirs))
+ return -ENAMETOOLONG;
+ for (i = 0; i < fsckcfg.dirstack.top; ++i)
+ if (inode.nid == fsckcfg.dirstack.dirs[i])
+ return -ELOOP;
+ fsckcfg.dirstack.dirs[fsckcfg.dirstack.top++] = pnid;
ret = erofs_iterate_dir(&ctx, true);
+ --fsckcfg.dirstack.top;
}
if (!ret && !erofs_is_packed_inode(&inode))
diff --git a/lib/dir.c b/lib/dir.c
index 1223cbc..d786a5b 100644
--- a/lib/dir.c
+++ b/lib/dir.c
@@ -179,7 +179,7 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
}
if (fsck && (ctx->flags & EROFS_READDIR_ALL_SPECIAL_FOUND) !=
- EROFS_READDIR_ALL_SPECIAL_FOUND) {
+ EROFS_READDIR_ALL_SPECIAL_FOUND && !err) {
erofs_err("`.' or `..' dirent is missing @ nid %llu",
dir->nid | 0ULL);
return -EFSCORRUPTED;
--
2.43.5
More information about the Linux-erofs
mailing list