From 08676a8c674c3522ffb3024dc34d8ae8b17b7d29 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Fri, 2 Dec 2022 11:28:24 +0800 Subject: [PATCH 1/7] anolis: erofs: fix erofs_is_fscache_mode() ANBZ: #6284 Both fscache and RAFS mode work without bdev, thus enhance erofs_is_fscache_mode() helper to make it distinguish from RAFS mode. Otherwise it can cause NULL crash when attempt to mount in RAFS mode, e.g. "mount -t erofs -o bootstrap_path=... none /mnt". BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 RIP: 0010:erofs_read_metabuf+0x145/0x190 [erofs] Call Trace: erofs_read_superblock+0x57/0x2a0 [erofs] erofs_fill_super+0x18b/0x280 [erofs] mount_nodev+0x48/0xa0 erofs_mount+0xbd/0x100 [erofs] mount_fs+0x35/0x160 vfs_kern_mount.part.9+0x54/0x110 do_mount+0x5af/0xc20 ksys_mount+0x80/0xd0 __x64_sys_mount+0x21/0x30 do_syscall_64+0x5b/0x1d0 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Reported-by: Hao Gou Fixes: e3ff139aa09c ("erofs: add fscache mode check helper") Signed-off-by: Jingbo Xu Reviewed-by: Joseph Qi Reviewed-by: Gao Xiang --- fs/erofs/internal.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 9ad9909cab54..2b1c9cddefb7 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -181,7 +181,9 @@ struct erofs_sb_info { static inline bool erofs_is_fscache_mode(struct super_block *sb) { - return IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && !sb->s_bdev; + /* to distinguish from rafsv6 which also works in nodev mode */ + return IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && !sb->s_bdev && + EROFS_SB(sb)->fsid; } enum { -- Gitee From dfa2c3ee758fcafadd56cb59a4e8860d6462ba88 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Wed, 30 Aug 2023 16:17:02 +0800 Subject: [PATCH 2/7] anolis: erofs: move option exclusion check to .get_tree() ANBZ: #6284 erofs_fc_parse_param() is called every time one mount option is parsed, and thus if "bootstrap_path" option is specified after "blob_dir_path" option, the mount will unexpectedly fail. Fixes this by moving the checking into .get_tree(), i.e. after all mount options have been parsed. Fixes: e1f156dedfe8 ("anolis: erofs: fix unclean iomap and uninitialized erofs_buf") Fixes: 3259f1c2326a ("anolis: erofs: make fscache and RAFS mode mutually exclusive") Reported-by: Gou Hao Signed-off-by: Jingbo Xu --- fs/erofs/super.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 4ce13a236c9d..457681233b1b 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -574,16 +574,6 @@ static int erofs_fc_parse_param(struct fs_context *fc, return -ENOPARAM; } - if (ctx->blob_dir_path && !ctx->bootstrap_path) { - errorfc(fc, "bootstrap_path required in RAFS mode"); - return -EINVAL; - } - - if (ctx->bootstrap_path && ctx->fsid) { - errorfc(fc, "fscache/RAFS modes are mutually exclusive"); - return -EINVAL; - } - return 0; } @@ -855,6 +845,16 @@ static int erofs_fc_get_tree(struct fs_context *fc) { struct erofs_fs_context *ctx = fc->fs_private; + if (ctx->blob_dir_path && !ctx->bootstrap_path) { + errorfc(fc, "bootstrap_path required in RAFS mode"); + return -EINVAL; + } + + if (ctx->bootstrap_path && ctx->fsid) { + errorfc(fc, "fscache/RAFS modes are mutually exclusive"); + return -EINVAL; + } + if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && ctx->fsid) return get_tree_nodev(fc, erofs_fc_fill_super); -- Gitee From b0bee8a9141e80e07e37ab146514a92faeccafe1 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Wed, 30 Aug 2023 19:46:54 +0800 Subject: [PATCH 3/7] anolis: erofs: no bother sb_set_blocksize() in rafsv6 mode ANBZ: #6284 Don't bother sb_set_blocksize() to set the initial block size in rafsv6 mode. This fixes the NULL crash due to sb->s_bdev is NULL in rafsv6 mode. BUG: kernel NULL pointer dereference, address: 000000000000 RIP: 0010:set_blocksize+0x23/0xd0 Call Trace: sb_set_blocksize+0x18/0x50 erofs_fc_fill_super+0xde/0x2a0 vfs_get_super+0x7b/0x110 vfs_get_tree+0x22/0xc0 path_mount+0x436/0x980 do_mount+0x59/0x80 __x64_sys_mount+0x8e/0xd0 do_syscall_64+0x30/0x40 entry_SYSCALL_64_after_hwframe+0x61/0xc6 Reported-by: Gou Hao Fixes: 20af86836304 ("anolis: erofs: support RAFS v6 over virtiofs") Signed-off-by: Jingbo Xu --- fs/erofs/super.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 457681233b1b..cc06cb0e59cf 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -747,10 +747,18 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) ctx->blob_dir_path = NULL; sbi->blkszbits = PAGE_SHIFT; - if (erofs_is_fscache_mode(sb)) { + if (!sb->s_bdev) { + /* fscache or rafsv6 mode */ sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; + } else { + if (!sb_set_blocksize(sb, PAGE_SIZE)) { + errorfc(fc, "failed to set initial blksize"); + return -EINVAL; + } + } + if (erofs_is_fscache_mode(sb)) { err = erofs_fscache_register_fs(sb); if (err) return err; @@ -758,11 +766,6 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) err = super_setup_bdi(sb); if (err) return err; - } else { - if (!sb_set_blocksize(sb, PAGE_SIZE)) { - errorfc(fc, "failed to set initial blksize"); - return -EINVAL; - } } err = erofs_read_superblock(sb); -- Gitee From 2a93fb2aa02d1947efff7ee321a9f6a818988630 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 31 Aug 2023 10:41:40 +0800 Subject: [PATCH 4/7] anolis: erofs: initialize bootstrap prior to reading superblock ANBZ: #6284 This fixes the NULL crash in rafsv6 mode due to attempt to read superblock while sbi->bootstrap has not been initialized yet. BUG: kernel NULL pointer dereference, address: 000000000000000 RIP: 0010:erofs_read_metabuf+0x46/0x50 Call Trace: erofs_read_superblock+0x40/0x220 erofs_fc_fill_super+0xfc/0x2c0 vfs_get_super+0x7b/0x110 vfs_get_tree+0x22/0xc0 path_mount+0x436/0x980 do_mount+0x59/0x80 __x64_sys_mount+0x8e/0xd0 do_syscall_64+0x30/0x40 entry_SYSCALL_64_after_hwframe+0x61/0xc6 Fixes: 20af86836304d ("anolis: erofs: support RAFS v6 over virtiofs") Signed-off-by: Jingbo Xu --- fs/erofs/super.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index cc06cb0e59cf..b7ace4316167 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -768,6 +768,10 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) return err; } + err = rafs_v6_fill_super(sb); + if (err) + return err; + err = erofs_read_superblock(sb); if (err) return err; @@ -786,10 +790,6 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) } } - err = rafs_v6_fill_super(sb); - if (err) - return err; - sb->s_time_gran = 1; sb->s_xattr = erofs_xattr_handlers; sb->s_export_op = &erofs_export_ops; -- Gitee From 55ca5449eda6047e3f0fcda7d13653a1b20b0e5a Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Thu, 31 Aug 2023 18:06:49 +0800 Subject: [PATCH 5/7] anolis: erofs: disable flatdev in rafsv6 mode ANBZ: #6284 flatdev only applies to the bdev based mode. Reported-by: Liu Bo Fixes: 20af86836304d ("anolis: erofs: support RAFS v6 over virtiofs") Signed-off-by: Jingbo Xu --- fs/erofs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/erofs/super.c b/fs/erofs/super.c index b7ace4316167..4c60da91c7c3 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -207,7 +207,7 @@ static int erofs_scan_devices(struct super_block *sb, if (!ondisk_extradevs) return 0; - if (!sbi->devs->extra_devices && !erofs_is_fscache_mode(sb)) + if (!sbi->devs->extra_devices && sb->s_bdev) sbi->devs->flatdev = true; sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1; -- Gitee From 68fb667157a4d95531ad65f1213a8c6b84454965 Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Fri, 5 May 2023 16:01:48 +0800 Subject: [PATCH 6/7] anolis: erofs: introduce erofs_is_rafsv6_mode() helper ANBZ: #6284 Introduce erofs_is_rafsv6_mode() helper to simplify the code. Signed-off-by: Jingbo Xu --- fs/erofs/data.c | 4 ++-- fs/erofs/inode.c | 16 +++++++++------- fs/erofs/internal.h | 5 +++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 777de4ae3dd7..20c806069161 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -56,7 +56,7 @@ void *__erofs_bread(struct super_block *sb, struct erofs_buf *buf, if (!page || page->index != index) { erofs_put_metabuf(buf); - if (sb && EROFS_SB(sb)->bootstrap) { + if (sb && erofs_is_rafsv6_mode(sb)) { unsigned int nofs_flag; nofs_flag = memalloc_nofs_save(); @@ -104,7 +104,7 @@ void *erofs_bread(struct erofs_buf *buf, struct inode *inode, void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb, erofs_blk_t blkaddr, enum erofs_kmap_type type) { - if (EROFS_SB(sb)->bootstrap) + if (erofs_is_rafsv6_mode(sb)) return __erofs_bread(sb, buf, EROFS_SB(sb)->bootstrap->f_inode, blkaddr, type); diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c index 4b3153fc6265..09d9d35c09f3 100644 --- a/fs/erofs/inode.c +++ b/fs/erofs/inode.c @@ -246,7 +246,6 @@ static int erofs_fill_inode(struct inode *inode) struct erofs_inode *vi = EROFS_I(inode); struct erofs_buf buf = __EROFS_BUF_INITIALIZER; struct super_block *sb = inode->i_sb; - struct erofs_sb_info *sbi = EROFS_SB(sb); void *kaddr; unsigned int ofs; int err = 0; @@ -265,7 +264,7 @@ static int erofs_fill_inode(struct inode *inode) if (erofs_inode_is_data_compressed(vi->datalayout)) { inode->i_fop = &generic_ro_fops; } else { - if (sbi->bootstrap) + if (erofs_is_rafsv6_mode(sb)) inode->i_fop = &rafs_v6_file_ro_fops; else inode->i_fop = &erofs_file_fops; @@ -301,15 +300,18 @@ static int erofs_fill_inode(struct inode *inode) err = -EOPNOTSUPP; goto out_unlock; } - if (sbi->bootstrap && !S_ISREG(inode->i_mode)) { - inode_nohighmem(inode); - inode->i_mapping->a_ops = &rafs_v6_aops; - } else if (inode->i_sb->s_bdev) { - inode->i_mapping->a_ops = &erofs_raw_access_aops; + + if (erofs_is_rafsv6_mode(sb)) { + if (!S_ISREG(inode->i_mode)) { + inode_nohighmem(inode); + inode->i_mapping->a_ops = &rafs_v6_aops; + } #ifdef CONFIG_EROFS_FS_ONDEMAND } else if (erofs_is_fscache_mode(inode->i_sb)) { inode->i_mapping->a_ops = &erofs_fscache_access_aops; #endif + } else { + inode->i_mapping->a_ops = &erofs_raw_access_aops; } out_unlock: diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 2b1c9cddefb7..f033443c7ebf 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -179,6 +179,11 @@ struct erofs_sb_info { #define set_opt(opt, option) ((opt)->mount_opt |= EROFS_MOUNT_##option) #define test_opt(opt, option) ((opt)->mount_opt & EROFS_MOUNT_##option) +static inline bool erofs_is_rafsv6_mode(struct super_block *sb) +{ + return !sb->s_bdev && EROFS_SB(sb)->bootstrap_path; +} + static inline bool erofs_is_fscache_mode(struct super_block *sb) { /* to distinguish from rafsv6 which also works in nodev mode */ -- Gitee From ff2e2261d30461a6652ba2f546bf6150b5c0a5d0 Mon Sep 17 00:00:00 2001 From: Huang Jianan Date: Fri, 12 May 2023 10:53:43 +0800 Subject: [PATCH 7/7] anolis: erofs: fix -EFAULT error due to KVEC iovec ANBZ: #6284 Other than the normal read(2) which generates ITER_IOVEC type iovec, other routine e.g. exec_binprm() may generate ITER_KVEC type iovec through kernel_read(), rafs_v6_read_chunk+0x2d4/0x2e0 rafs_v6_file_read_iter+0x128/0x200 do_iter_readv_writev+0x130/0x170 do_iter_read+0x9c/0x180 vfs_iter_read+0x20/0x30 ovl_read_iter+0x1ac/0x214 __kernel_read+0xf0/0x274 kernel_read+0x6c/0xb0 search_binary_handler+0x48/0x2b4 exec_binprm+0x58/0x19c bprm_execve+0x160/0x1f0 do_execveat_common+0x1c0/0x230 __arm64_sys_execve+0x44/0x54 Make rafs_v6_read_chunk capable of handling ITER_KVEC type iovec. Signed-off-by: Huang Jianan [ liubo: make error message distinguishable for iovec types ] Signed-off-by: Liu Bo [ jingbo: polish commit message ] Signed-off-by: Jingbo Xu --- fs/erofs/inode.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c index 09d9d35c09f3..e38dd912818e 100644 --- a/fs/erofs/inode.c +++ b/fs/erofs/inode.c @@ -427,7 +427,17 @@ static ssize_t rafs_v6_read_chunk(struct super_block *sb, pr_debug("pipe ret %ld off %llu size %llu read %ld\n", ret, off, size, read); if (ret <= 0) { - pr_err("%s: failed to read blob ret %ld\n", __func__, ret); + pr_err("%s: pipe failed to read blob ret %ld\n", __func__, ret); + return ret; + } + } else if (iov_iter_is_kvec(to)) { + iov_iter_kvec(&titer, READ, to->kvec, 1, size - read); + + ret = vfs_iter_read(mdev.m_fp, &titer, &off, 0); + pr_debug("kvec ret %ld off %llu size %llu read %ld\n", + ret, off, size, read); + if (ret <= 0) { + pr_err("%s: kvec failed to read blob ret %ld\n", __func__, ret); return ret; } } else { @@ -443,7 +453,7 @@ static ssize_t rafs_v6_read_chunk(struct super_block *sb, iov_iter_init(&titer, READ, &iovec, 1, iovec.iov_len); ret = vfs_iter_read(mdev.m_fp, &titer, &off, 0); if (ret <= 0) { - pr_err("%s: failed to read blob ret %ld\n", __func__, ret); + pr_err("%s: iovec failed to read blob ret %ld\n", __func__, ret); return ret; } else if (ret < iovec.iov_len) { return read; -- Gitee