From: Greg Kroah-Hartman Date: Wed, 4 Jan 2023 15:00:33 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v6.1.4~29 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=827e3f7a3f1ca4fbc226b4e53cca8aa545b4998c;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: ext4-add-ext4_iget_bad-flag-to-prevent-unexpected-bad-inode.patch ext4-add-helper-to-check-quota-inums.patch ext4-add-inode-table-check-in-__ext4_get_inode_loc-to-aovid-possible-infinite-loop.patch ext4-check-and-assert-if-marking-an-no_delete-evicting-inode-dirty.patch ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-boot-loader-inode.patch ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-quota-inode.patch ext4-fix-reserved-cluster-accounting-in-__es_remove_extent.patch ext4-fix-undefined-behavior-in-bit-shift-for-ext4_check_flag_values.patch ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch ext4-remove-trailing-newline-from-ext4_msg-message.patch ext4-silence-the-warning-when-evicting-inode-with-dioread_nolock.patch fs-ext4-initialize-fsdata-in-pagecache_write.patch --- diff --git a/queue-5.15/ext4-add-ext4_iget_bad-flag-to-prevent-unexpected-bad-inode.patch b/queue-5.15/ext4-add-ext4_iget_bad-flag-to-prevent-unexpected-bad-inode.patch new file mode 100644 index 00000000000..804bde82735 --- /dev/null +++ b/queue-5.15/ext4-add-ext4_iget_bad-flag-to-prevent-unexpected-bad-inode.patch @@ -0,0 +1,72 @@ +From 63b1e9bccb71fe7d7e3ddc9877dbdc85e5d2d023 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 26 Oct 2022 12:23:09 +0800 +Subject: ext4: add EXT4_IGET_BAD flag to prevent unexpected bad inode + +From: Baokun Li + +commit 63b1e9bccb71fe7d7e3ddc9877dbdc85e5d2d023 upstream. + +There are many places that will get unhappy (and crash) when ext4_iget() +returns a bad inode. However, if iget the boot loader inode, allows a bad +inode to be returned, because the inode may not be initialized. This +mechanism can be used to bypass some checks and cause panic. To solve this +problem, we add a special iget flag EXT4_IGET_BAD. Only with this flag +we'd be returning bad inode from ext4_iget(), otherwise we always return +the error code if the inode is bad inode.(suggested by Jan Kara) + +Signed-off-by: Baokun Li +Reviewed-by: Jason Yan +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20221026042310.3839669-4-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ext4.h | 3 ++- + fs/ext4/inode.c | 8 +++++++- + fs/ext4/ioctl.c | 3 ++- + 3 files changed, 11 insertions(+), 3 deletions(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2996,7 +2996,8 @@ int do_journal_get_write_access(handle_t + typedef enum { + EXT4_IGET_NORMAL = 0, + EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */ +- EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */ ++ EXT4_IGET_HANDLE = 0x0002, /* Inode # is from a handle */ ++ EXT4_IGET_BAD = 0x0004 /* Allow to iget a bad inode */ + } ext4_iget_flags; + + extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4885,8 +4885,14 @@ struct inode *__ext4_iget(struct super_b + if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb)) + ext4_error_inode(inode, function, line, 0, + "casefold flag without casefold feature"); +- brelse(iloc.bh); ++ if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) { ++ ext4_error_inode(inode, function, line, 0, ++ "bad inode without EXT4_IGET_BAD flag"); ++ ret = -EUCLEAN; ++ goto bad_inode; ++ } + ++ brelse(iloc.bh); + unlock_new_inode(inode); + return inode; + +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -124,7 +124,8 @@ static long swap_inode_boot_loader(struc + blkcnt_t blocks; + unsigned short bytes; + +- inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL); ++ inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, ++ EXT4_IGET_SPECIAL | EXT4_IGET_BAD); + if (IS_ERR(inode_bl)) + return PTR_ERR(inode_bl); + ei_bl = EXT4_I(inode_bl); diff --git a/queue-5.15/ext4-add-helper-to-check-quota-inums.patch b/queue-5.15/ext4-add-helper-to-check-quota-inums.patch new file mode 100644 index 00000000000..203e5fa1a11 --- /dev/null +++ b/queue-5.15/ext4-add-helper-to-check-quota-inums.patch @@ -0,0 +1,78 @@ +From 07342ec259df2a35d6a34aebce010567a80a0e15 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 26 Oct 2022 12:23:08 +0800 +Subject: ext4: add helper to check quota inums + +From: Baokun Li + +commit 07342ec259df2a35d6a34aebce010567a80a0e15 upstream. + +Before quota is enabled, a check on the preset quota inums in +ext4_super_block is added to prevent wrong quota inodes from being loaded. +In addition, when the quota fails to be enabled, the quota type and quota +inum are printed to facilitate fault locating. + +Signed-off-by: Baokun Li +Reviewed-by: Jason Yan +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20221026042310.3839669-3-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/super.c | 28 +++++++++++++++++++++++++--- + 1 file changed, 25 insertions(+), 3 deletions(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -6309,6 +6309,20 @@ static int ext4_quota_on(struct super_bl + return err; + } + ++static inline bool ext4_check_quota_inum(int type, unsigned long qf_inum) ++{ ++ switch (type) { ++ case USRQUOTA: ++ return qf_inum == EXT4_USR_QUOTA_INO; ++ case GRPQUOTA: ++ return qf_inum == EXT4_GRP_QUOTA_INO; ++ case PRJQUOTA: ++ return qf_inum >= EXT4_GOOD_OLD_FIRST_INO; ++ default: ++ BUG(); ++ } ++} ++ + static int ext4_quota_enable(struct super_block *sb, int type, int format_id, + unsigned int flags) + { +@@ -6325,9 +6339,16 @@ static int ext4_quota_enable(struct supe + if (!qf_inums[type]) + return -EPERM; + ++ if (!ext4_check_quota_inum(type, qf_inums[type])) { ++ ext4_error(sb, "Bad quota inum: %lu, type: %d", ++ qf_inums[type], type); ++ return -EUCLEAN; ++ } ++ + qf_inode = ext4_iget(sb, qf_inums[type], EXT4_IGET_SPECIAL); + if (IS_ERR(qf_inode)) { +- ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]); ++ ext4_error(sb, "Bad quota inode: %lu, type: %d", ++ qf_inums[type], type); + return PTR_ERR(qf_inode); + } + +@@ -6366,8 +6387,9 @@ int ext4_enable_quotas(struct super_bloc + if (err) { + ext4_warning(sb, + "Failed to enable quota tracking " +- "(type=%d, err=%d). Please run " +- "e2fsck to fix.", type, err); ++ "(type=%d, err=%d, ino=%lu). " ++ "Please run e2fsck to fix.", type, ++ err, qf_inums[type]); + for (type--; type >= 0; type--) { + struct inode *inode; + diff --git a/queue-5.15/ext4-add-inode-table-check-in-__ext4_get_inode_loc-to-aovid-possible-infinite-loop.patch b/queue-5.15/ext4-add-inode-table-check-in-__ext4_get_inode_loc-to-aovid-possible-infinite-loop.patch new file mode 100644 index 00000000000..08edb2c0f4b --- /dev/null +++ b/queue-5.15/ext4-add-inode-table-check-in-__ext4_get_inode_loc-to-aovid-possible-infinite-loop.patch @@ -0,0 +1,83 @@ +From eee22187b53611e173161e38f61de1c7ecbeb876 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 17 Aug 2022 21:27:01 +0800 +Subject: ext4: add inode table check in __ext4_get_inode_loc to aovid possible infinite loop + +From: Baokun Li + +commit eee22187b53611e173161e38f61de1c7ecbeb876 upstream. + +In do_writepages, if the value returned by ext4_writepages is "-ENOMEM" +and "wbc->sync_mode == WB_SYNC_ALL", retry until the condition is not met. + +In __ext4_get_inode_loc, if the bh returned by sb_getblk is NULL, +the function returns -ENOMEM. + +In __getblk_slow, if the return value of grow_buffers is less than 0, +the function returns NULL. + +When the three processes are connected in series like the following stack, +an infinite loop may occur: + +do_writepages <--- keep retrying + ext4_writepages + mpage_map_and_submit_extent + mpage_map_one_extent + ext4_map_blocks + ext4_ext_map_blocks + ext4_ext_handle_unwritten_extents + ext4_ext_convert_to_initialized + ext4_split_extent + ext4_split_extent_at + __ext4_ext_dirty + __ext4_mark_inode_dirty + ext4_reserve_inode_write + ext4_get_inode_loc + __ext4_get_inode_loc <--- return -ENOMEM + sb_getblk + __getblk_gfp + __getblk_slow <--- return NULL + grow_buffers + grow_dev_page <--- return -ENXIO + ret = (block < end_block) ? 1 : -ENXIO; + +In this issue, bg_inode_table_hi is overwritten as an incorrect value. +As a result, `block < end_block` cannot be met in grow_dev_page. +Therefore, __ext4_get_inode_loc always returns '-ENOMEM' and do_writepages +keeps retrying. As a result, the writeback process is in the D state due +to an infinite loop. + +Add a check on inode table block in the __ext4_get_inode_loc function by +referring to ext4_read_inode_bitmap to avoid this infinite loop. + +Cc: stable@kernel.org +Signed-off-by: Baokun Li +Reviewed-by: Ritesh Harjani (IBM) +Link: https://lore.kernel.org/r/20220817132701.3015912-3-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4299,9 +4299,17 @@ static int __ext4_get_inode_loc(struct s + inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; + inode_offset = ((ino - 1) % + EXT4_INODES_PER_GROUP(sb)); +- block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block); + iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb); + ++ block = ext4_inode_table(sb, gdp); ++ if ((block <= le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) || ++ (block >= ext4_blocks_count(EXT4_SB(sb)->s_es))) { ++ ext4_error(sb, "Invalid inode table block %llu in " ++ "block_group %u", block, iloc->block_group); ++ return -EFSCORRUPTED; ++ } ++ block += (inode_offset / inodes_per_block); ++ + bh = sb_getblk(sb, block); + if (unlikely(!bh)) + return -ENOMEM; diff --git a/queue-5.15/ext4-check-and-assert-if-marking-an-no_delete-evicting-inode-dirty.patch b/queue-5.15/ext4-check-and-assert-if-marking-an-no_delete-evicting-inode-dirty.patch new file mode 100644 index 00000000000..d0ffdf4515c --- /dev/null +++ b/queue-5.15/ext4-check-and-assert-if-marking-an-no_delete-evicting-inode-dirty.patch @@ -0,0 +1,42 @@ +From 318cdc822c63b6e2befcfdc2088378ae6fa18def Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Wed, 29 Jun 2022 19:26:47 +0800 +Subject: ext4: check and assert if marking an no_delete evicting inode dirty + +From: Zhang Yi + +commit 318cdc822c63b6e2befcfdc2088378ae6fa18def upstream. + +In ext4_evict_inode(), if we evicting an inode in the 'no_delete' path, +it cannot be raced by another mark_inode_dirty(). If it happens, +someone else may accidentally dirty it without holding inode refcount +and probably cause use-after-free issues in the writeback procedure. +It's indiscoverable and hard to debug, so add an WARN_ON_ONCE() to +check and detect this issue in advance. + +Suggested-by: Jan Kara +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20220629112647.4141034-2-yi.zhang@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -338,6 +338,12 @@ stop_handle: + ext4_xattr_inode_array_free(ea_inode_array); + return; + no_delete: ++ /* ++ * Check out some where else accidentally dirty the evicting inode, ++ * which may probably cause inode use-after-free issues later. ++ */ ++ WARN_ON_ONCE(!list_empty_careful(&inode->i_io_list)); ++ + if (!list_empty(&EXT4_I(inode)->i_fc_list)) + ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_NOMEM, NULL); + ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ diff --git a/queue-5.15/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-boot-loader-inode.patch b/queue-5.15/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-boot-loader-inode.patch new file mode 100644 index 00000000000..123d1850e99 --- /dev/null +++ b/queue-5.15/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-boot-loader-inode.patch @@ -0,0 +1,96 @@ +From 991ed014de0840c5dc405b679168924afb2952ac Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 26 Oct 2022 12:23:10 +0800 +Subject: ext4: fix bug_on in __es_tree_search caused by bad boot loader inode + +From: Baokun Li + +commit 991ed014de0840c5dc405b679168924afb2952ac upstream. + +We got a issue as fllows: +================================================================== + kernel BUG at fs/ext4/extents_status.c:203! + invalid opcode: 0000 [#1] PREEMPT SMP + CPU: 1 PID: 945 Comm: cat Not tainted 6.0.0-next-20221007-dirty #349 + RIP: 0010:ext4_es_end.isra.0+0x34/0x42 + RSP: 0018:ffffc9000143b768 EFLAGS: 00010203 + RAX: 0000000000000000 RBX: ffff8881769cd0b8 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: ffffffff8fc27cf7 RDI: 00000000ffffffff + RBP: ffff8881769cd0bc R08: 0000000000000000 R09: ffffc9000143b5f8 + R10: 0000000000000001 R11: 0000000000000001 R12: ffff8881769cd0a0 + R13: ffff8881768e5668 R14: 00000000768e52f0 R15: 0000000000000000 + FS: 00007f359f7f05c0(0000)GS:ffff88842fd00000(0000)knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007f359f5a2000 CR3: 000000017130c000 CR4: 00000000000006e0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + Call Trace: + + __es_tree_search.isra.0+0x6d/0xf5 + ext4_es_cache_extent+0xfa/0x230 + ext4_cache_extents+0xd2/0x110 + ext4_find_extent+0x5d5/0x8c0 + ext4_ext_map_blocks+0x9c/0x1d30 + ext4_map_blocks+0x431/0xa50 + ext4_mpage_readpages+0x48e/0xe40 + ext4_readahead+0x47/0x50 + read_pages+0x82/0x530 + page_cache_ra_unbounded+0x199/0x2a0 + do_page_cache_ra+0x47/0x70 + page_cache_ra_order+0x242/0x400 + ondemand_readahead+0x1e8/0x4b0 + page_cache_sync_ra+0xf4/0x110 + filemap_get_pages+0x131/0xb20 + filemap_read+0xda/0x4b0 + generic_file_read_iter+0x13a/0x250 + ext4_file_read_iter+0x59/0x1d0 + vfs_read+0x28f/0x460 + ksys_read+0x73/0x160 + __x64_sys_read+0x1e/0x30 + do_syscall_64+0x35/0x80 + entry_SYSCALL_64_after_hwframe+0x63/0xcd + +================================================================== + +In the above issue, ioctl invokes the swap_inode_boot_loader function to +swap inode<5> and inode<12>. However, inode<5> contain incorrect imode and +disordered extents, and i_nlink is set to 1. The extents check for inode in +the ext4_iget function can be bypassed bacause 5 is EXT4_BOOT_LOADER_INO. +While links_count is set to 1, the extents are not initialized in +swap_inode_boot_loader. After the ioctl command is executed successfully, +the extents are swapped to inode<12>, in this case, run the `cat` command +to view inode<12>. And Bug_ON is triggered due to the incorrect extents. + +When the boot loader inode is not initialized, its imode can be one of the +following: +1) the imode is a bad type, which is marked as bad_inode in ext4_iget and + set to S_IFREG. +2) the imode is good type but not S_IFREG. +3) the imode is S_IFREG. + +The BUG_ON may be triggered by bypassing the check in cases 1 and 2. +Therefore, when the boot loader inode is bad_inode or its imode is not +S_IFREG, initialize the inode to avoid triggering the BUG. + +Signed-off-by: Baokun Li +Reviewed-by: Jason Yan +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20221026042310.3839669-5-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ioctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -175,7 +175,7 @@ static long swap_inode_boot_loader(struc + /* Protect extent tree against block allocations via delalloc */ + ext4_double_down_write_data_sem(inode, inode_bl); + +- if (inode_bl->i_nlink == 0) { ++ if (is_bad_inode(inode_bl) || !S_ISREG(inode_bl->i_mode)) { + /* this inode has never been used as a BOOT_LOADER */ + set_nlink(inode_bl, 1); + i_uid_write(inode_bl, 0); diff --git a/queue-5.15/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-quota-inode.patch b/queue-5.15/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-quota-inode.patch new file mode 100644 index 00000000000..98ca74d417b --- /dev/null +++ b/queue-5.15/ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-quota-inode.patch @@ -0,0 +1,109 @@ +From d323877484765aaacbb2769b06e355c2041ed115 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 26 Oct 2022 12:23:07 +0800 +Subject: ext4: fix bug_on in __es_tree_search caused by bad quota inode + +From: Baokun Li + +commit d323877484765aaacbb2769b06e355c2041ed115 upstream. + +We got a issue as fllows: +================================================================== + kernel BUG at fs/ext4/extents_status.c:202! + invalid opcode: 0000 [#1] PREEMPT SMP + CPU: 1 PID: 810 Comm: mount Not tainted 6.1.0-rc1-next-g9631525255e3 #352 + RIP: 0010:__es_tree_search.isra.0+0xb8/0xe0 + RSP: 0018:ffffc90001227900 EFLAGS: 00010202 + RAX: 0000000000000000 RBX: 0000000077512a0f RCX: 0000000000000000 + RDX: 0000000000000002 RSI: 0000000000002a10 RDI: ffff8881004cd0c8 + RBP: ffff888177512ac8 R08: 47ffffffffffffff R09: 0000000000000001 + R10: 0000000000000001 R11: 00000000000679af R12: 0000000000002a10 + R13: ffff888177512d88 R14: 0000000077512a10 R15: 0000000000000000 + FS: 00007f4bd76dbc40(0000)GS:ffff88842fd00000(0000)knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00005653bf993cf8 CR3: 000000017bfdf000 CR4: 00000000000006e0 + DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 + DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + Call Trace: + + ext4_es_cache_extent+0xe2/0x210 + ext4_cache_extents+0xd2/0x110 + ext4_find_extent+0x5d5/0x8c0 + ext4_ext_map_blocks+0x9c/0x1d30 + ext4_map_blocks+0x431/0xa50 + ext4_getblk+0x82/0x340 + ext4_bread+0x14/0x110 + ext4_quota_read+0xf0/0x180 + v2_read_header+0x24/0x90 + v2_check_quota_file+0x2f/0xa0 + dquot_load_quota_sb+0x26c/0x760 + dquot_load_quota_inode+0xa5/0x190 + ext4_enable_quotas+0x14c/0x300 + __ext4_fill_super+0x31cc/0x32c0 + ext4_fill_super+0x115/0x2d0 + get_tree_bdev+0x1d2/0x360 + ext4_get_tree+0x19/0x30 + vfs_get_tree+0x26/0xe0 + path_mount+0x81d/0xfc0 + do_mount+0x8d/0xc0 + __x64_sys_mount+0xc0/0x160 + do_syscall_64+0x35/0x80 + entry_SYSCALL_64_after_hwframe+0x63/0xcd + +================================================================== + +Above issue may happen as follows: +------------------------------------- +ext4_fill_super + ext4_orphan_cleanup + ext4_enable_quotas + ext4_quota_enable + ext4_iget --> get error inode <5> + ext4_ext_check_inode --> Wrong imode makes it escape inspection + make_bad_inode(inode) --> EXT4_BOOT_LOADER_INO set imode + dquot_load_quota_inode + vfs_setup_quota_inode --> check pass + dquot_load_quota_sb + v2_check_quota_file + v2_read_header + ext4_quota_read + ext4_bread + ext4_getblk + ext4_map_blocks + ext4_ext_map_blocks + ext4_find_extent + ext4_cache_extents + ext4_es_cache_extent + __es_tree_search.isra.0 + ext4_es_end --> Wrong extents trigger BUG_ON + +In the above issue, s_usr_quota_inum is set to 5, but inode<5> contains +incorrect imode and disordered extents. Because 5 is EXT4_BOOT_LOADER_INO, +the ext4_ext_check_inode check in the ext4_iget function can be bypassed, +finally, the extents that are not checked trigger the BUG_ON in the +__es_tree_search function. To solve this issue, check whether the inode is +bad_inode in vfs_setup_quota_inode(). + +Signed-off-by: Baokun Li +Reviewed-by: Chaitanya Kulkarni +Reviewed-by: Jason Yan +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20221026042310.3839669-2-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/quota/dquot.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -2317,6 +2317,8 @@ static int vfs_setup_quota_inode(struct + struct super_block *sb = inode->i_sb; + struct quota_info *dqopt = sb_dqopt(sb); + ++ if (is_bad_inode(inode)) ++ return -EUCLEAN; + if (!S_ISREG(inode->i_mode)) + return -EACCES; + if (IS_RDONLY(inode)) diff --git a/queue-5.15/ext4-fix-reserved-cluster-accounting-in-__es_remove_extent.patch b/queue-5.15/ext4-fix-reserved-cluster-accounting-in-__es_remove_extent.patch new file mode 100644 index 00000000000..98dbca3bf70 --- /dev/null +++ b/queue-5.15/ext4-fix-reserved-cluster-accounting-in-__es_remove_extent.patch @@ -0,0 +1,91 @@ +From 1da18e38cb97e9521e93d63034521a9649524f64 Mon Sep 17 00:00:00 2001 +From: Ye Bin +Date: Thu, 8 Dec 2022 11:34:24 +0800 +Subject: ext4: fix reserved cluster accounting in __es_remove_extent() + +From: Ye Bin + +commit 1da18e38cb97e9521e93d63034521a9649524f64 upstream. + +When bigalloc is enabled, reserved cluster accounting for delayed +allocation is handled in extent_status.c. With a corrupted file +system, it's possible for this accounting to be incorrect, +dsicovered by Syzbot: + +EXT4-fs error (device loop0): ext4_validate_block_bitmap:398: comm rep: + bg 0: block 5: invalid block bitmap +EXT4-fs (loop0): Delayed block allocation failed for inode 18 at logical + offset 0 with max blocks 32 with error 28 +EXT4-fs (loop0): This should not happen!! Data will be lost + +EXT4-fs (loop0): Total free blocks count 0 +EXT4-fs (loop0): Free/Dirty block details +EXT4-fs (loop0): free_blocks=0 +EXT4-fs (loop0): dirty_blocks=32 +EXT4-fs (loop0): Block reservation details +EXT4-fs (loop0): i_reserved_data_blocks=2 +EXT4-fs (loop0): Inode 18 (00000000845cd634): + i_reserved_data_blocks (1) not cleared! + +Above issue happens as follows: +Assume: +sbi->s_cluster_ratio = 16 +Step1: +Insert delay block [0, 31] -> ei->i_reserved_data_blocks=2 +Step2: +ext4_writepages + mpage_map_and_submit_extent -> return failed + mpage_release_unused_pages -> to release [0, 30] + ext4_es_remove_extent -> remove lblk=0 end=30 + __es_remove_extent -> len1=0 len2=31-30=1 + __es_remove_extent: + ... + if (len2 > 0) { + ... + if (len1 > 0) { + ... + } else { + es->es_lblk = end + 1; + es->es_len = len2; + ... + } + if (count_reserved) + count_rsvd(inode, lblk, ...); + goto out; -> will return but didn't calculate 'reserved' + ... +Step3: +ext4_destroy_inode -> trigger "i_reserved_data_blocks (1) not cleared!" + +To solve above issue if 'len2>0' call 'get_rsvd()' before goto out. + +Reported-by: syzbot+05a0f0ccab4a25626e38@syzkaller.appspotmail.com +Fixes: 8fcc3a580651 ("ext4: rework reserved cluster accounting when invalidating pages") +Signed-off-by: Ye Bin +Reviewed-by: Eric Whitney +Link: https://lore.kernel.org/r/20221208033426.1832460-2-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/extents_status.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/ext4/extents_status.c ++++ b/fs/ext4/extents_status.c +@@ -1372,7 +1372,7 @@ retry: + if (count_reserved) + count_rsvd(inode, lblk, orig_es.es_len - len1 - len2, + &orig_es, &rc); +- goto out; ++ goto out_get_reserved; + } + + if (len1 > 0) { +@@ -1414,6 +1414,7 @@ retry: + } + } + ++out_get_reserved: + if (count_reserved) + *reserved = get_rsvd(inode, end, es, &rc); + out: diff --git a/queue-5.15/ext4-fix-undefined-behavior-in-bit-shift-for-ext4_check_flag_values.patch b/queue-5.15/ext4-fix-undefined-behavior-in-bit-shift-for-ext4_check_flag_values.patch new file mode 100644 index 00000000000..76465919322 --- /dev/null +++ b/queue-5.15/ext4-fix-undefined-behavior-in-bit-shift-for-ext4_check_flag_values.patch @@ -0,0 +1,48 @@ +From 3bf678a0f9c017c9ba7c581541dbc8453452a7ae Mon Sep 17 00:00:00 2001 +From: Gaosheng Cui +Date: Mon, 31 Oct 2022 13:58:33 +0800 +Subject: ext4: fix undefined behavior in bit shift for ext4_check_flag_values + +From: Gaosheng Cui + +commit 3bf678a0f9c017c9ba7c581541dbc8453452a7ae upstream. + +Shifting signed 32-bit value by 31 bits is undefined, so changing +significant bit to unsigned. The UBSAN warning calltrace like below: + +UBSAN: shift-out-of-bounds in fs/ext4/ext4.h:591:2 +left shift of 1 by 31 places cannot be represented in type 'int' +Call Trace: + + dump_stack_lvl+0x7d/0xa5 + dump_stack+0x15/0x1b + ubsan_epilogue+0xe/0x4e + __ubsan_handle_shift_out_of_bounds+0x1e7/0x20c + ext4_init_fs+0x5a/0x277 + do_one_initcall+0x76/0x430 + kernel_init_freeable+0x3b3/0x422 + kernel_init+0x24/0x1e0 + ret_from_fork+0x1f/0x30 + + +Fixes: 9a4c80194713 ("ext4: ensure Inode flags consistency are checked at build time") +Signed-off-by: Gaosheng Cui +Link: https://lore.kernel.org/r/20221031055833.3966222-1-cuigaosheng1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ext4.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -559,7 +559,7 @@ enum { + * + * It's not paranoia if the Murphy's Law really *is* out to get you. :-) + */ +-#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG)) ++#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1U << EXT4_INODE_##FLAG)) + #define CHECK_FLAG_VALUE(FLAG) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG)) + + static inline void ext4_check_flag_values(void) diff --git a/queue-5.15/ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch b/queue-5.15/ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch new file mode 100644 index 00000000000..e55926c6551 --- /dev/null +++ b/queue-5.15/ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch @@ -0,0 +1,75 @@ +From a71248b1accb2b42e4980afef4fa4a27fa0e36f5 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 2 Nov 2022 16:06:33 +0800 +Subject: ext4: fix use-after-free in ext4_orphan_cleanup + +From: Baokun Li + +commit a71248b1accb2b42e4980afef4fa4a27fa0e36f5 upstream. + +I caught a issue as follows: +================================================================== + BUG: KASAN: use-after-free in __list_add_valid+0x28/0x1a0 + Read of size 8 at addr ffff88814b13f378 by task mount/710 + + CPU: 1 PID: 710 Comm: mount Not tainted 6.1.0-rc3-next #370 + Call Trace: + + dump_stack_lvl+0x73/0x9f + print_report+0x25d/0x759 + kasan_report+0xc0/0x120 + __asan_load8+0x99/0x140 + __list_add_valid+0x28/0x1a0 + ext4_orphan_cleanup+0x564/0x9d0 [ext4] + __ext4_fill_super+0x48e2/0x5300 [ext4] + ext4_fill_super+0x19f/0x3a0 [ext4] + get_tree_bdev+0x27b/0x450 + ext4_get_tree+0x19/0x30 [ext4] + vfs_get_tree+0x49/0x150 + path_mount+0xaae/0x1350 + do_mount+0xe2/0x110 + __x64_sys_mount+0xf0/0x190 + do_syscall_64+0x35/0x80 + entry_SYSCALL_64_after_hwframe+0x63/0xcd + + [...] +================================================================== + +Above issue may happen as follows: +------------------------------------- +ext4_fill_super + ext4_orphan_cleanup + --- loop1: assume last_orphan is 12 --- + list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan) + ext4_truncate --> return 0 + ext4_inode_attach_jinode --> return -ENOMEM + iput(inode) --> free inode<12> + --- loop2: last_orphan is still 12 --- + list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); + // use inode<12> and trigger UAF + +To solve this issue, we need to propagate the return value of +ext4_inode_attach_jinode() appropriately. + +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20221102080633.1630225-1-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4198,7 +4198,8 @@ int ext4_truncate(struct inode *inode) + + /* If we zero-out tail of the page, we have to create jinode for jbd2 */ + if (inode->i_size & (inode->i_sb->s_blocksize - 1)) { +- if (ext4_inode_attach_jinode(inode) < 0) ++ err = ext4_inode_attach_jinode(inode); ++ if (err) + goto out_trace; + } + diff --git a/queue-5.15/ext4-remove-trailing-newline-from-ext4_msg-message.patch b/queue-5.15/ext4-remove-trailing-newline-from-ext4_msg-message.patch new file mode 100644 index 00000000000..3aa5e5c5af3 --- /dev/null +++ b/queue-5.15/ext4-remove-trailing-newline-from-ext4_msg-message.patch @@ -0,0 +1,35 @@ +From 78742d4d056df7d2fad241c90185d281bf924844 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= +Date: Tue, 11 Oct 2022 16:57:58 +0100 +Subject: ext4: remove trailing newline from ext4_msg() message +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Luís Henriques + +commit 78742d4d056df7d2fad241c90185d281bf924844 upstream. + +The ext4_msg() function adds a new line to the message. Remove extra '\n' +from call to ext4_msg() in ext4_orphan_cleanup(). + +Signed-off-by: Luís Henriques +Link: https://lore.kernel.org/r/20221011155758.15287-1-lhenriques@suse.de +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/orphan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/orphan.c ++++ b/fs/ext4/orphan.c +@@ -412,7 +412,7 @@ void ext4_orphan_cleanup(struct super_bl + /* don't clear list on RO mount w/ errors */ + if (es->s_last_orphan && !(s_flags & SB_RDONLY)) { + ext4_msg(sb, KERN_INFO, "Errors on filesystem, " +- "clearing orphan list.\n"); ++ "clearing orphan list."); + es->s_last_orphan = 0; + } + jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); diff --git a/queue-5.15/ext4-silence-the-warning-when-evicting-inode-with-dioread_nolock.patch b/queue-5.15/ext4-silence-the-warning-when-evicting-inode-with-dioread_nolock.patch new file mode 100644 index 00000000000..ae65cfcc391 --- /dev/null +++ b/queue-5.15/ext4-silence-the-warning-when-evicting-inode-with-dioread_nolock.patch @@ -0,0 +1,93 @@ +From bc12ac98ea2e1b70adc6478c8b473a0003b659d3 Mon Sep 17 00:00:00 2001 +From: Zhang Yi +Date: Wed, 29 Jun 2022 19:26:46 +0800 +Subject: ext4: silence the warning when evicting inode with dioread_nolock + +From: Zhang Yi + +commit bc12ac98ea2e1b70adc6478c8b473a0003b659d3 upstream. + +When evicting an inode with default dioread_nolock, it could be raced by +the unwritten extents converting kworker after writeback some new +allocated dirty blocks. It convert unwritten extents to written, the +extents could be merged to upper level and free extent blocks, so it +could mark the inode dirty again even this inode has been marked +I_FREEING. But the inode->i_io_list check and warning in +ext4_evict_inode() missing this corner case. Fortunately, +ext4_evict_inode() will wait all extents converting finished before this +check, so it will not lead to inode use-after-free problem, every thing +is OK besides this warning. The WARN_ON_ONCE was originally designed +for finding inode use-after-free issues in advance, but if we add +current dioread_nolock case in, it will become not quite useful, so fix +this warning by just remove this check. + + ====== + WARNING: CPU: 7 PID: 1092 at fs/ext4/inode.c:227 + ext4_evict_inode+0x875/0xc60 + ... + RIP: 0010:ext4_evict_inode+0x875/0xc60 + ... + Call Trace: + + evict+0x11c/0x2b0 + iput+0x236/0x3a0 + do_unlinkat+0x1b4/0x490 + __x64_sys_unlinkat+0x4c/0xb0 + do_syscall_64+0x3b/0x90 + entry_SYSCALL_64_after_hwframe+0x46/0xb0 + RIP: 0033:0x7fa933c1115b + ====== + +rm kworker + ext4_end_io_end() +vfs_unlink() + ext4_unlink() + ext4_convert_unwritten_io_end_vec() + ext4_convert_unwritten_extents() + ext4_map_blocks() + ext4_ext_map_blocks() + ext4_ext_try_to_merge_up() + __mark_inode_dirty() + check !I_FREEING + locked_inode_to_wb_and_lock_list() + iput() + iput_final() + evict() + ext4_evict_inode() + truncate_inode_pages_final() //wait release io_end + inode_io_list_move_locked() + ext4_release_io_end() + trigger WARN_ON_ONCE() + +Cc: stable@kernel.org +Fixes: ceff86fddae8 ("ext4: Avoid freeing inodes on dirty list") +Signed-off-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20220629112647.4141034-1-yi.zhang@huawei.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -225,13 +225,13 @@ void ext4_evict_inode(struct inode *inod + + /* + * For inodes with journalled data, transaction commit could have +- * dirtied the inode. Flush worker is ignoring it because of I_FREEING +- * flag but we still need to remove the inode from the writeback lists. ++ * dirtied the inode. And for inodes with dioread_nolock, unwritten ++ * extents converting worker could merge extents and also have dirtied ++ * the inode. Flush worker is ignoring it because of I_FREEING flag but ++ * we still need to remove the inode from the writeback lists. + */ +- if (!list_empty_careful(&inode->i_io_list)) { +- WARN_ON_ONCE(!ext4_should_journal_data(inode)); ++ if (!list_empty_careful(&inode->i_io_list)) + inode_io_list_del(inode); +- } + + /* + * Protect us against freezing - iput() caller didn't have to have any diff --git a/queue-5.15/fs-ext4-initialize-fsdata-in-pagecache_write.patch b/queue-5.15/fs-ext4-initialize-fsdata-in-pagecache_write.patch new file mode 100644 index 00000000000..d32b9a7649d --- /dev/null +++ b/queue-5.15/fs-ext4-initialize-fsdata-in-pagecache_write.patch @@ -0,0 +1,38 @@ +From 956510c0c7439e90b8103aaeaf4da92878c622f0 Mon Sep 17 00:00:00 2001 +From: Alexander Potapenko +Date: Mon, 21 Nov 2022 12:21:30 +0100 +Subject: fs: ext4: initialize fsdata in pagecache_write() + +From: Alexander Potapenko + +commit 956510c0c7439e90b8103aaeaf4da92878c622f0 upstream. + +When aops->write_begin() does not initialize fsdata, KMSAN reports +an error passing the latter to aops->write_end(). + +Fix this by unconditionally initializing fsdata. + +Cc: Eric Biggers +Fixes: c93d8f885809 ("ext4: add basic fs-verity support") +Reported-by: syzbot+9767be679ef5016b6082@syzkaller.appspotmail.com +Signed-off-by: Alexander Potapenko +Reviewed-by: Eric Biggers +Link: https://lore.kernel.org/r/20221121112134.407362-1-glider@google.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/verity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/ext4/verity.c ++++ b/fs/ext4/verity.c +@@ -76,7 +76,7 @@ static int pagecache_write(struct inode + size_t n = min_t(size_t, count, + PAGE_SIZE - offset_in_page(pos)); + struct page *page; +- void *fsdata; ++ void *fsdata = NULL; + int res; + + res = pagecache_write_begin(NULL, inode->i_mapping, pos, n, 0, diff --git a/queue-5.15/series b/queue-5.15/series index 5b374b2cbd6..ac58daad503 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -138,3 +138,15 @@ drm-vmwgfx-validate-the-box-size-for-the-snooped-cursor.patch drm-i915-dsi-fix-vbt-send-packet-port-selection-for-dual-link-dsi.patch drm-ingenic-fix-missing-platform_driver_unregister-call-in-ingenic_drm_init.patch arm64-efi-execute-runtime-services-from-a-dedicated-stack.patch +ext4-silence-the-warning-when-evicting-inode-with-dioread_nolock.patch +ext4-add-inode-table-check-in-__ext4_get_inode_loc-to-aovid-possible-infinite-loop.patch +ext4-remove-trailing-newline-from-ext4_msg-message.patch +fs-ext4-initialize-fsdata-in-pagecache_write.patch +ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch +ext4-fix-undefined-behavior-in-bit-shift-for-ext4_check_flag_values.patch +ext4-add-ext4_iget_bad-flag-to-prevent-unexpected-bad-inode.patch +ext4-add-helper-to-check-quota-inums.patch +ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-quota-inode.patch +ext4-fix-reserved-cluster-accounting-in-__es_remove_extent.patch +ext4-check-and-assert-if-marking-an-no_delete-evicting-inode-dirty.patch +ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-boot-loader-inode.patch