From: Greg Kroah-Hartman Date: Wed, 15 Mar 2023 08:18:44 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v4.14.310~44 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0992712009e92e1b4fcf4ebdfcfe7ff231868853;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: ext4-add-strict-range-checks-while-freeing-blocks.patch ext4-block-range-must-be-validated-before-use-in-ext4_mb_clear_bb.patch --- diff --git a/queue-5.15/ext4-add-strict-range-checks-while-freeing-blocks.patch b/queue-5.15/ext4-add-strict-range-checks-while-freeing-blocks.patch new file mode 100644 index 00000000000..59054ff8053 --- /dev/null +++ b/queue-5.15/ext4-add-strict-range-checks-while-freeing-blocks.patch @@ -0,0 +1,66 @@ +From a00b482b82fb098956a5bed22bd7873e56f152f1 Mon Sep 17 00:00:00 2001 +From: Ritesh Harjani +Date: Wed, 16 Feb 2022 12:32:50 +0530 +Subject: ext4: add strict range checks while freeing blocks + +From: Ritesh Harjani + +commit a00b482b82fb098956a5bed22bd7873e56f152f1 upstream. + +Currently ext4_mb_clear_bb() & ext4_group_add_blocks() only checks +whether the given block ranges (which is to be freed) belongs to any FS +metadata blocks or not, of the block's respective block group. +But to detect any FS error early, it is better to add more strict +checkings in those functions which checks whether the given blocks +belongs to any critical FS metadata or not within system-zone. + +Suggested-by: Jan Kara +Signed-off-by: Ritesh Harjani +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/ddd9143d064774e32d6364a99667817c6e8bfdc0.1644992610.git.riteshh@linux.ibm.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Tudor Ambarus +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/mballoc.c | 16 +++------------- + 1 file changed, 3 insertions(+), 13 deletions(-) + +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5946,13 +5946,7 @@ do_more: + goto error_return; + } + +- if (in_range(ext4_block_bitmap(sb, gdp), block, count) || +- in_range(ext4_inode_bitmap(sb, gdp), block, count) || +- in_range(block, ext4_inode_table(sb, gdp), +- sbi->s_itb_per_group) || +- in_range(block + count - 1, ext4_inode_table(sb, gdp), +- sbi->s_itb_per_group)) { +- ++ if (!ext4_inode_block_valid(inode, block, count)) { + ext4_error(sb, "Freeing blocks in system zone - " + "Block = %llu, count = %lu", block, count); + /* err = 0. ext4_std_error should be a no op */ +@@ -6023,7 +6017,7 @@ do_more: + NULL); + if (err && err != -EOPNOTSUPP) + ext4_msg(sb, KERN_WARNING, "discard request in" +- " group:%d block:%d count:%lu failed" ++ " group:%u block:%d count:%lu failed" + " with %d", block_group, bit, count, + err); + } else +@@ -6236,11 +6230,7 @@ int ext4_group_add_blocks(handle_t *hand + goto error_return; + } + +- if (in_range(ext4_block_bitmap(sb, desc), block, count) || +- in_range(ext4_inode_bitmap(sb, desc), block, count) || +- in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) || +- in_range(block + count - 1, ext4_inode_table(sb, desc), +- sbi->s_itb_per_group)) { ++ if (!ext4_sb_block_valid(sb, NULL, block, count)) { + ext4_error(sb, "Adding blocks in system zones - " + "Block = %llu, count = %lu", + block, count); diff --git a/queue-5.15/ext4-block-range-must-be-validated-before-use-in-ext4_mb_clear_bb.patch b/queue-5.15/ext4-block-range-must-be-validated-before-use-in-ext4_mb_clear_bb.patch new file mode 100644 index 00000000000..91361ae44a6 --- /dev/null +++ b/queue-5.15/ext4-block-range-must-be-validated-before-use-in-ext4_mb_clear_bb.patch @@ -0,0 +1,143 @@ +From 1e1c2b86ef86a8477fd9b9a4f48a6bfe235606f6 Mon Sep 17 00:00:00 2001 +From: Lukas Czerner +Date: Thu, 14 Jul 2022 18:59:03 +0200 +Subject: ext4: block range must be validated before use in ext4_mb_clear_bb() + +From: Lukas Czerner + +commit 1e1c2b86ef86a8477fd9b9a4f48a6bfe235606f6 upstream. + +Block range to free is validated in ext4_free_blocks() using +ext4_inode_block_valid() and then it's passed to ext4_mb_clear_bb(). +However in some situations on bigalloc file system the range might be +adjusted after the validation in ext4_free_blocks() which can lead to +troubles on corrupted file systems such as one found by syzkaller that +resulted in the following BUG + +kernel BUG at fs/ext4/ext4.h:3319! +PREEMPT SMP NOPTI +CPU: 28 PID: 4243 Comm: repro Kdump: loaded Not tainted 5.19.0-rc6+ #1 +Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1.fc35 04/01/2014 +RIP: 0010:ext4_free_blocks+0x95e/0xa90 +Call Trace: + + ? lock_timer_base+0x61/0x80 + ? __es_remove_extent+0x5a/0x760 + ? __mod_timer+0x256/0x380 + ? ext4_ind_truncate_ensure_credits+0x90/0x220 + ext4_clear_blocks+0x107/0x1b0 + ext4_free_data+0x15b/0x170 + ext4_ind_truncate+0x214/0x2c0 + ? _raw_spin_unlock+0x15/0x30 + ? ext4_discard_preallocations+0x15a/0x410 + ? ext4_journal_check_start+0xe/0x90 + ? __ext4_journal_start_sb+0x2f/0x110 + ext4_truncate+0x1b5/0x460 + ? __ext4_journal_start_sb+0x2f/0x110 + ext4_evict_inode+0x2b4/0x6f0 + evict+0xd0/0x1d0 + ext4_enable_quotas+0x11f/0x1f0 + ext4_orphan_cleanup+0x3de/0x430 + ? proc_create_seq_private+0x43/0x50 + ext4_fill_super+0x295f/0x3ae0 + ? snprintf+0x39/0x40 + ? sget_fc+0x19c/0x330 + ? ext4_reconfigure+0x850/0x850 + get_tree_bdev+0x16d/0x260 + vfs_get_tree+0x25/0xb0 + path_mount+0x431/0xa70 + __x64_sys_mount+0xe2/0x120 + do_syscall_64+0x5b/0x80 + ? do_user_addr_fault+0x1e2/0x670 + ? exc_page_fault+0x70/0x170 + entry_SYSCALL_64_after_hwframe+0x46/0xb0 +RIP: 0033:0x7fdf4e512ace + +Fix it by making sure that the block range is properly validated before +used every time it changes in ext4_free_blocks() or ext4_mb_clear_bb(). + +Link: https://syzkaller.appspot.com/bug?id=5266d464285a03cee9dbfda7d2452a72c3c2ae7c +Reported-by: syzbot+15cd994e273307bf5cfa@syzkaller.appspotmail.com +Signed-off-by: Lukas Czerner +Cc: Tadeusz Struk +Tested-by: Tadeusz Struk +Link: https://lore.kernel.org/r/20220714165903.58260-1-lczerner@redhat.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Tudor Ambarus +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/mballoc.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5916,6 +5916,15 @@ static void ext4_mb_clear_bb(handle_t *h + + sbi = EXT4_SB(sb); + ++ if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) && ++ !ext4_inode_block_valid(inode, block, count)) { ++ ext4_error(sb, "Freeing blocks in system zone - " ++ "Block = %llu, count = %lu", block, count); ++ /* err = 0. ext4_std_error should be a no op */ ++ goto error_return; ++ } ++ flags |= EXT4_FREE_BLOCKS_VALIDATED; ++ + do_more: + overflow = 0; + ext4_get_group_no_and_offset(sb, block, &block_group, &bit); +@@ -5932,6 +5941,8 @@ do_more: + overflow = EXT4_C2B(sbi, bit) + count - + EXT4_BLOCKS_PER_GROUP(sb); + count -= overflow; ++ /* The range changed so it's no longer validated */ ++ flags &= ~EXT4_FREE_BLOCKS_VALIDATED; + } + count_clusters = EXT4_NUM_B2C(sbi, count); + bitmap_bh = ext4_read_block_bitmap(sb, block_group); +@@ -5946,7 +5957,8 @@ do_more: + goto error_return; + } + +- if (!ext4_inode_block_valid(inode, block, count)) { ++ if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) && ++ !ext4_inode_block_valid(inode, block, count)) { + ext4_error(sb, "Freeing blocks in system zone - " + "Block = %llu, count = %lu", block, count); + /* err = 0. ext4_std_error should be a no op */ +@@ -6069,6 +6081,8 @@ do_more: + block += count; + count = overflow; + put_bh(bitmap_bh); ++ /* The range changed so it's no longer validated */ ++ flags &= ~EXT4_FREE_BLOCKS_VALIDATED; + goto do_more; + } + error_return: +@@ -6115,6 +6129,7 @@ void ext4_free_blocks(handle_t *handle, + "block = %llu, count = %lu", block, count); + return; + } ++ flags |= EXT4_FREE_BLOCKS_VALIDATED; + + ext4_debug("freeing block %llu\n", block); + trace_ext4_free_blocks(inode, block, count, flags); +@@ -6146,6 +6161,8 @@ void ext4_free_blocks(handle_t *handle, + block -= overflow; + count += overflow; + } ++ /* The range changed so it's no longer validated */ ++ flags &= ~EXT4_FREE_BLOCKS_VALIDATED; + } + overflow = EXT4_LBLK_COFF(sbi, count); + if (overflow) { +@@ -6156,6 +6173,8 @@ void ext4_free_blocks(handle_t *handle, + return; + } else + count += sbi->s_cluster_ratio - overflow; ++ /* The range changed so it's no longer validated */ ++ flags &= ~EXT4_FREE_BLOCKS_VALIDATED; + } + + if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) { diff --git a/queue-5.15/series b/queue-5.15/series index 6bc7903f8a6..2f092bbcdfc 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -124,3 +124,5 @@ sched-uclamp-fix-a-uninitialized-variable-warnings.patch sched-fair-fixes-for-capacity-inversion-detection.patch ext4-refactor-ext4_free_blocks-to-pull-out-ext4_mb_clear_bb.patch ext4-add-ext4_sb_block_valid-refactored-out-of-ext4_inode_block_valid.patch +ext4-add-strict-range-checks-while-freeing-blocks.patch +ext4-block-range-must-be-validated-before-use-in-ext4_mb_clear_bb.patch