erofs-utils: fsck: refuse illegel filename
authorGuo Xuenan <guoxuenan@huawei.com>
Tue, 5 Sep 2023 02:32:07 +0000 (10:32 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 5 Sep 2023 02:51:52 +0000 (10:51 +0800)
In some crafted erofs images, fsck.erofs may write outside the
destination directory, which may be used to do some dangerous things.

This commit fixes by checking all directory entry names with a '/'
character when fscking.  Squashfs also met the same situation [1],
and have already fixed it here [2].

[1] https://github.com/plougher/squashfs-tools/issues/72
[2] https://github.com/plougher/squashfs-tools/commit/79b5a555058eef4e1e7ff220c344d39f8cd09646

Fixes: 412c8f908132 ("erofs-utils: fsck: add --extract=X support to extract to path X")
Reviewed-by: Guo Xuenan <guoxuenan@huawei.com>
Signed-off-by: Guo Xuenan <guoxuenan@huawei.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20230905023207.70314-1-hsiangkao@linux.alibaba.com
lib/dir.c

index fff0bc076fb34b5e6b60cd6bb5a820b033b552ec..1223cbc822d1103787a20301e0672ee226f2adf9 100644 (file)
--- a/lib/dir.c
+++ b/lib/dir.c
@@ -4,6 +4,19 @@
 #include "erofs/print.h"
 #include "erofs/dir.h"
 
+/* filename should not have a '/' in the name string */
+static bool erofs_validate_filename(const char *dname, int size)
+{
+       char *name = (char *)dname;
+
+       while (name - dname < size && *name != '\0') {
+               if (*name == '/')
+                       return false;
+               ++name;
+       }
+       return true;
+}
+
 static int traverse_dirents(struct erofs_dir_context *ctx,
                            void *dentry_blk, unsigned int lblk,
                            unsigned int next_nameoff, unsigned int maxsize,
@@ -102,6 +115,10 @@ static int traverse_dirents(struct erofs_dir_context *ctx,
                                }
                                break;
                        }
+               } else if (fsck &&
+                          !erofs_validate_filename(de_name, de_namelen)) {
+                       errmsg = "corrupted dirent with illegal filename";
+                       goto out;
                }
                ret = ctx->cb(ctx);
                if (ret) {