FAILED: patch "[PATCH] ext4: allow ext4_get_group_info() to fail" failed to apply to 5.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.4.y
git checkout FETCH_HEAD
git cherry-pick -x 5354b2af34064a4579be8bc0e2f15a7b70f14b5f
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023051536-tripping-expire-2e97@gregkh' --subject-prefix 'PATCH 5.4.y' HEAD^..
Possible dependencies:
5354b2af3406 ("ext4: allow ext4_get_group_info() to fail")fa08a7b61dff ("ext4: fix WARNING in mb_find_extent")01e4ca294517 ("ext4: allow to find by goal if EXT4_MB_HINT_GOAL_ONLY is set") a6c75eaf1103 ("ext4: add mballoc stats proc file")67d251860461 ("ext4: drop s_mb_bal_lock and convert protected fields to atomic") 8016e29f4362 ("ext4: fast commit recovery path")5b849b5f96b4 ("jbd2: fast commit recovery path")aa75f4d3daae ("ext4: main fast-commit commit path")ff780b91efe9 ("jbd2: add fast commit machinery")6866d7b3f2bb ("ext4 / jbd2: add fast commit initialization") 995a3ed67fc8 ("ext4: add fast_commit feature and handling for extended mount options") 2d069c0889ef ("ext4: use common helpers in all places reading metadata buffers") d9befedaafcf ("ext4: clear buffer verified flag if read meta block from disk") 15ed2851b0f4 ("ext4: remove unused argument from ext4_(inc|dec)_count") dddcd2f9ebde ("ext4: optimize the implementation of ext4_mb_good_group()") 3d392b2676bf ("ext4: add prefetch_block_bitmaps mount option") ab74c7b23f37 ("ext4: indicate via a block bitmap read is prefetched via a tracepoint") bc71726c7257 ("ext4: abort the filesystem if failed to async write metadata buffer") cfd732377221 ("ext4: add prefetching for block allocation bitmaps") e5f78159d62f ("ext4: lost matching-pair of trace in ext4_unlink")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 5354b2af34064a4579be8bc0e2f15a7b70f14b5f Mon Sep 17 00:00:00 2001
From: Theodore Ts'o <[email protected]>
Date: Sat, 29 Apr 2023 00:06:28 -0400
Subject: [PATCH] ext4: allow ext4_get_group_info() to fail
Previously, ext4_get_group_info() would treat an invalid group number as BUG(), since in theory it should never happen. However, if a malicious attaker (or fuzzer) modifies the superblock via the block device while it is the file system is mounted, it is possible for s_first_data_block to get set to a very large number. In that case, when calculating the block group of some block number (such as the starting block of a preallocation region), could result in an underflow and very large block group number. Then the BUG_ON check in ext4_get_group_info() would fire, resutling in a denial of service attack that can be triggered by root or someone with write access to the block device.
For a quality of implementation perspective, it's best that even if the system administrator does something that they shouldn't, that it will not trigger a BUG. So instead of BUG'ing, ext4_get_group_info() will call ext4_error and return NULL. We also add fallback code in all of the callers of ext4_get_group_info() that it might NULL.
Also, since ext4_get_group_info() was already borderline to be an inline function, un-inline it. The results in a next reduction of the compiled text size of ext4 by roughly 2k.
fs/ext4/balloc.c +17 -1
@@ -321,6 +321,22 @@ static ext4_fsblk_t ext4_valid_block_bitmap_padding(struct super_block *sb,return (next_zero_bit < bitmap_size ? next_zero_bit :0 ); } +struct ext4_group_info *ext4_get_group_info (struct super_block *sb, +ext4_group_t group) +{ +struct ext4_group_info **grp_info; +long indexv, indexh; + +if (unlikely (group >=EXT4_SB (sb)->s_groups_count)) { +ext4_error (sb,"invalid group %u" , group); +return NULL ; + } + indexv = group >> (EXT4_DESC_PER_BLOCK_BITS (sb)); + indexh = group & ((EXT4_DESC_PER_BLOCK (sb)) -1 ); + grp_info =sbi_array_rcu_deref (EXT4_SB (sb), s_group_info, indexv); +return grp_info[indexh]; +} +/* * Return the block number which was discovered to be invalid, or 0 if * the block bitmap is valid.
@@ -395,7 +411,7 @@ static int ext4_validate_block_bitmap(struct super_block *sb,if (buffer_verified (bh))return 0 ; -if (EXT4_MB_GRP_BBITMAP_CORRUPT (grp)) +if (!grp ||EXT4_MB_GRP_BBITMAP_CORRUPT (grp))return -EFSCORRUPTED ;ext4_lock_group (sb, block_group);
fs/ext4/ext4.h +2 -13
@@ -2625,6 +2625,8 @@ extern void ext4_check_blocks_bitmap(struct super_block *);extern struct ext4_group_desc *ext4_get_group_desc (struct super_block * sb,ext4_group_t block_group,struct buffer_head ** bh); +extern struct ext4_group_info *ext4_get_group_info (struct super_block *sb, +ext4_group_t group);extern int ext4_should_retry_alloc (struct super_block *sb,int *retries); extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb,
@@ -3232,19 +3234,6 @@ static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size) raw_inode->i_size_high =cpu_to_le32 (i_size >>32 ); } -static inline -struct ext4_group_info *ext4_get_group_info (struct super_block *sb, -ext4_group_t group) -{ -struct ext4_group_info **grp_info; -long indexv, indexh; -BUG_ON (group >=EXT4_SB (sb)->s_groups_count); - indexv = group >> (EXT4_DESC_PER_BLOCK_BITS (sb)); - indexh = group & ((EXT4_DESC_PER_BLOCK (sb)) -1 ); - grp_info =sbi_array_rcu_deref (EXT4_SB (sb), s_group_info, indexv); -return grp_info[indexh]; -} -/* * Reading s_groups_count requires using smp_rmb() afterwards. See * the locking protocol documented in the comments of ext4_group_add()
fs/ext4/ialloc.c +8 -4
@@ -91,7 +91,7 @@ static int ext4_validate_inode_bitmap(struct super_block *sb,if (buffer_verified (bh))return 0 ; -if (EXT4_MB_GRP_IBITMAP_CORRUPT (grp)) +if (!grp ||EXT4_MB_GRP_IBITMAP_CORRUPT (grp))return -EFSCORRUPTED ;ext4_lock_group (sb, block_group);
@@ -293,7 +293,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) }if (!(sbi->s_mount_state &EXT4_FC_REPLAY )) { grp =ext4_get_group_info (sb, block_group); -if (unlikely (EXT4_MB_GRP_IBITMAP_CORRUPT (grp))) { +if (!grp ||unlikely (EXT4_MB_GRP_IBITMAP_CORRUPT (grp))) { fatal = -EFSCORRUPTED ; goto error_return; }
@@ -1046,7 +1046,7 @@ struct inode *__ext4_new_inode(struct mnt_idmap *idmap,* Skip groups with already-known suspicious inode * tables */ -if (EXT4_MB_GRP_IBITMAP_CORRUPT (grp)) +if (!grp ||EXT4_MB_GRP_IBITMAP_CORRUPT (grp)) goto next_group; }
@@ -1183,6 +1183,10 @@ struct inode *__ext4_new_inode(struct mnt_idmap *idmap,if (!(sbi->s_mount_state &EXT4_FC_REPLAY )) { grp =ext4_get_group_info (sb, group); +if (!grp) { + err = -EFSCORRUPTED ; + goto out; + }down_read (&grp->alloc_sem);/* * protect vs itable * lazyinit
@@ -1526,7 +1530,7 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, } gdp =ext4_get_group_desc (sb, group, &group_desc_bh); -if (!gdp) +if (!gdp || !grp) goto out;/*
fs/ext4/mballoc.c +53 -11
215 lines not on this page · raw message
fs/ext4/super.c +2 -0
@@ -1048,6 +1048,8 @@ void ext4_mark_group_bitmap_corrupted(struct super_block *sb,struct ext4_group_desc *gdp =ext4_get_group_desc (sb, group,NULL );int ret; +if (!grp || !gdp) +return ;if (flags &EXT4_GROUP_INFO_BBITMAP_CORRUPT ) { ret =ext4_test_and_set_bit (EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT , &grp->bb_state);