[lvc-project] [PATCH 2/3] ext2: validate bg_block_bitmap before sb_getblk() in read_block_bitmap()

Denis Zubov d.zubov at tssltd.ru
Tue May 12 15:22:14 MSK 2026


read_block_bitmap() blindly trusts desc->bg_block_bitmap and calls
sb_getblk() on it. For a corrupt on-disk group descriptor that points
outside the filesystem, sb_getblk() returns a bh whose b_data sits on
a bdev-cache page that can be reclaimed back to the buddy allocator,
producing a KASAN use-after-free when ext2_try_to_allocate() writes
a bit via ext2_set_bit_atomic():

BUG: KASAN: use-after-free in ext2_try_to_allocate+0x5fd/0x840
Write of size 8 at addr ffff888007104000
...
ext2_try_to_allocate_with_rsv+0x121b/0x1580
ext2_new_blocks+0x671/0x1650
ext2_get_blocks+0x76b/0x2340
...
ext2_make_empty+0xff/0x7e0
ext2_mkdir+0x153/0x240

Reject bg_block_bitmap values outside [s_first_data_block,
s_blocks_count) before creating any buffer head for them.

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: 8b91582500ae ("ext2: retry block allocation if new blocks are allocated from system zone")
Signed-off-by: Denis Zubov <d.zubov at tssltd.ru>
---
 fs/ext2/balloc.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index bc181aa47265..10e3b100d390 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -128,6 +128,7 @@ static int ext2_valid_block_bitmap(struct super_block *sb,
 static struct buffer_head *
 read_block_bitmap(struct super_block *sb, unsigned int block_group)
 {
+	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	struct ext2_group_desc * desc;
 	struct buffer_head * bh = NULL;
 	ext2_fsblk_t bitmap_blk;
@@ -137,6 +138,16 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
 	if (!desc)
 		return NULL;
 	bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
+
+	if (bitmap_blk < le32_to_cpu(sbi->s_es->s_first_data_block) ||
+	    bitmap_blk >= le32_to_cpu(sbi->s_es->s_blocks_count)) {
+		ext2_error(sb, __func__,
+			   "Invalid block_bitmap = %llu for group %u (s_blocks_count = %u)",
+			   (unsigned long long)bitmap_blk, block_group,
+			   le32_to_cpu(sbi->s_es->s_blocks_count));
+		return NULL;
+	}
+
 	bh = sb_getblk(sb, bitmap_blk);
 	if (unlikely(!bh)) {
 		ext2_error(sb, __func__,
-- 
2.53.0




More information about the lvc-project mailing list