Skip to content

Commit 5b5b4f8

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix to do sanity check on .cp_pack_total_block_count
As bughunter reported in bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215709 f2fs may hang when mounting a fuzzed image, the dmesg shows as below: __filemap_get_folio+0x3a9/0x590 pagecache_get_page+0x18/0x60 __get_meta_page+0x95/0x460 [f2fs] get_checkpoint_version+0x2a/0x1e0 [f2fs] validate_checkpoint+0x8e/0x2a0 [f2fs] f2fs_get_valid_checkpoint+0xd0/0x620 [f2fs] f2fs_fill_super+0xc01/0x1d40 [f2fs] mount_bdev+0x18a/0x1c0 f2fs_mount+0x15/0x20 [f2fs] legacy_get_tree+0x28/0x50 vfs_get_tree+0x27/0xc0 path_mount+0x480/0xaa0 do_mount+0x7c/0xa0 __x64_sys_mount+0x8b/0xe0 do_syscall_64+0x38/0xc0 entry_SYSCALL_64_after_hwframe+0x44/0xae The root cause is cp_pack_total_block_count field in checkpoint was fuzzed to one, as calcuated, two cp pack block locates in the same block address, so then read latter cp pack block, it will block on the page lock due to the lock has already held when reading previous cp pack block, fix it by adding sanity check for cp_pack_total_block_count. Cc: [email protected] Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent e60aeb2 commit 5b5b4f8

File tree

1 file changed

+5
-3
lines changed

1 file changed

+5
-3
lines changed

fs/f2fs/checkpoint.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -875,22 +875,24 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
875875
struct page *cp_page_1 = NULL, *cp_page_2 = NULL;
876876
struct f2fs_checkpoint *cp_block = NULL;
877877
unsigned long long cur_version = 0, pre_version = 0;
878+
unsigned int cp_blocks;
878879
int err;
879880

880881
err = get_checkpoint_version(sbi, cp_addr, &cp_block,
881882
&cp_page_1, version);
882883
if (err)
883884
return NULL;
884885

885-
if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
886-
sbi->blocks_per_seg) {
886+
cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count);
887+
888+
if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) {
887889
f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u",
888890
le32_to_cpu(cp_block->cp_pack_total_block_count));
889891
goto invalid_cp;
890892
}
891893
pre_version = *version;
892894

893-
cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
895+
cp_addr += cp_blocks - 1;
894896
err = get_checkpoint_version(sbi, cp_addr, &cp_block,
895897
&cp_page_2, version);
896898
if (err)

0 commit comments

Comments
 (0)