From: Zhang Yi yi.zhang@huawei.com
hulk inclusion category: bugfix bugzilla: 186835, https://gitee.com/openeuler/kernel/issues/I59KJ1?from=project-issue CVE: NA
---------------------------
We capture a NULL pointer issue when resizing a corrupt ext4 image which freshly clear resize_inode feature (not run e2fsck). It could be simply reproduced by following steps. The problem is because of the resize_inode feature was cleared, and it will convert the filesystem to meta_bg mode in ext4_resize_fs(), but the es->s_reserved_gdt_blocks was not cleared together, so could we mistakenly call reserve_backup_gdb() and passing an uninitialized resize_inode to it when adding new group descriptors.
mkfs.ext4 /dev/sda 3G tune2fs -O ^resize_inode /dev/sda #forget to run requested e2fsck mount /dev/sda /mnt resize2fs /dev/sda 8G
======== BUG: kernel NULL pointer dereference, address: 0000000000000028 CPU: 19 PID: 3243 Comm: resize2fs Not tainted 5.18.0-rc7-00001-gfde086c5ebfd #748 ... RIP: 0010:ext4_flex_group_add+0xe08/0x2570 ... Call Trace: <TASK> ext4_resize_fs+0xbec/0x1660 __ext4_ioctl+0x1749/0x24e0 ext4_ioctl+0x12/0x20 __x64_sys_ioctl+0xa6/0x110 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae RIP: 0033:0x7f2dd739617b ========
The fix is simple, add a check in ext4_resize_fs() to make sure that the es->s_reserved_gdt_blocks is zero when the resize_inode feature is disabled.
Signed-off-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Li Lingfeng lilingfeng3@huawei.com Reviewed-by: zhihao Cheng chengzhihao1@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/ext4/resize.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index bd0d185654f3..4a0a9fd7ee2a 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -2006,6 +2006,9 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) ext4_warning(sb, "Error opening resize inode"); return PTR_ERR(resize_inode); } + } else if (es->s_reserved_gdt_blocks) { + ext4_error(sb, "resize_inode disabled but reserved GDT blocks non-zero"); + return -EFSCORRUPTED; }
if ((!resize_inode && !meta_bg) || n_blocks_count == o_blocks_count) {