[lvc-project] [PATCH] ext2: fix use-after-free in read_block_bitmap()
Denis Zubov
d.zubov at tssltd.ru
Sun Apr 26 12:17:42 MSK 2026
When bh_read() returns 0 (buffer already uptodate), read_block_bitmap()
skips ext2_valid_block_bitmap() and returns the buffer_head without
validation. On a corrupt filesystem with an invalid block bitmap this
allows a corrupt bh to propagate to ext2_try_to_allocate(), where
ext2_set_bit_atomic() writes to bitmap_bh->b_data of an already freed
page, causing a use-after-free write.
The comment 'continue with corrupt bitmap' suggests this was intentional,
however continuing with an invalid bitmap leads to memory corruption.
The correct behavior on a corrupt filesystem is to return NULL so all
callers handle the error safely via the existing io_error path.
Fix by always running ext2_valid_block_bitmap() before returning bh,
regardless of whether the buffer was cached or freshly read, and
returning NULL with brelse() on validation failure.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Signed-off-by: Denis Zubov <d.zubov at tssltd.ru>
---
fs/ext2/balloc.c | 30 +++++++++++++-----------------
1 file changed, 13 insertions(+), 17 deletions(-)
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index b8cfab8f98b9..3345a25b4bde 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -146,23 +146,19 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
return NULL;
}
ret = bh_read(bh, 0);
- if (ret > 0)
- return bh;
- if (ret < 0) {
- brelse(bh);
- ext2_error(sb, __func__,
- "Cannot read block bitmap - "
- "block_group = %d, block_bitmap = %u",
- block_group, le32_to_cpu(desc->bg_block_bitmap));
- return NULL;
- }
-
- ext2_valid_block_bitmap(sb, desc, block_group, bh);
- /*
- * file system mounted not to panic on error, continue with corrupt
- * bitmap
- */
- return bh;
+ if (ret < 0) {
+ brelse(bh);
+ ext2_error(sb, __func__,
+ "Cannot read block bitmap - "
+ "block_group = %d, block_bitmap = %u",
+ block_group, le32_to_cpu(desc->bg_block_bitmap));
+ return NULL;
+ }
+ if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) {
+ brelse(bh);
+ return NULL;
+ }
+ return bh;
}
static void group_adjust_blocks(struct super_block *sb, int group_no,
--
2.53.0
More information about the lvc-project
mailing list