--- /dev/null
+From a00b482b82fb098956a5bed22bd7873e56f152f1 Mon Sep 17 00:00:00 2001
+From: Ritesh Harjani <riteshh@linux.ibm.com>
+Date: Wed, 16 Feb 2022 12:32:50 +0530
+Subject: ext4: add strict range checks while freeing blocks
+
+From: Ritesh Harjani <riteshh@linux.ibm.com>
+
+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 <jack@suse.cz>
+Signed-off-by: Ritesh Harjani <riteshh@linux.ibm.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/ddd9143d064774e32d6364a99667817c6e8bfdc0.1644992610.git.riteshh@linux.ibm.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/mballoc.c | 16 +++-------------
+ 1 file changed, 3 insertions(+), 13 deletions(-)
+
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5361,13 +5361,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 */
+@@ -5437,7 +5431,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
+@@ -5650,11 +5644,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);
--- /dev/null
+From 1e1c2b86ef86a8477fd9b9a4f48a6bfe235606f6 Mon Sep 17 00:00:00 2001
+From: Lukas Czerner <lczerner@redhat.com>
+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 <lczerner@redhat.com>
+
+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:
+ <TASK>
+ ? 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 <lczerner@redhat.com>
+Cc: Tadeusz Struk <tadeusz.struk@linaro.org>
+Tested-by: Tadeusz Struk <tadeusz.struk@linaro.org>
+Link: https://lore.kernel.org/r/20220714165903.58260-1-lczerner@redhat.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/mballoc.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5331,6 +5331,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);
+@@ -5347,6 +5356,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);
+@@ -5361,7 +5372,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 */
+@@ -5483,6 +5495,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:
+@@ -5529,6 +5543,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);
+@@ -5560,6 +5575,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) {
+@@ -5570,6 +5587,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)) {