f2fs: fix to do sanity check for sb/cp fields correctly
authorChao Yu <chao@kernel.org>
Fri, 6 Aug 2021 00:04:37 +0000 (08:04 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 18 Sep 2021 11:40:10 +0000 (13:40 +0200)
commit 65ddf6564843890a58ee3b18bb46ce67d96333fb upstream.

This patch fixes below problems of sb/cp sanity check:
- in sanity_check_raw_superi(), it missed to consider log header
blocks while cp_payload check.
- in f2fs_sanity_check_ckpt(), it missed to check nat_bits_blocks.

Cc: <stable@kernel.org>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/f2fs/super.c

index 476b2c4..dad91b1 100644 (file)
@@ -2898,11 +2898,13 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
                return -EFSCORRUPTED;
        }
 
-       if (le32_to_cpu(raw_super->cp_payload) >
-                               (blocks_per_seg - F2FS_CP_PACKS)) {
-               f2fs_info(sbi, "Insane cp_payload (%u > %u)",
+       if (le32_to_cpu(raw_super->cp_payload) >=
+                               (blocks_per_seg - F2FS_CP_PACKS -
+                               NR_CURSEG_PERSIST_TYPE)) {
+               f2fs_info(sbi, "Insane cp_payload (%u >= %u)",
                          le32_to_cpu(raw_super->cp_payload),
-                         blocks_per_seg - F2FS_CP_PACKS);
+                         blocks_per_seg - F2FS_CP_PACKS -
+                         NR_CURSEG_PERSIST_TYPE);
                return -EFSCORRUPTED;
        }
 
@@ -2938,6 +2940,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        unsigned int cp_pack_start_sum, cp_payload;
        block_t user_block_count, valid_user_blocks;
        block_t avail_node_count, valid_node_count;
+       unsigned int nat_blocks, nat_bits_bytes, nat_bits_blocks;
        int i, j;
 
        total = le32_to_cpu(raw_super->segment_count);
@@ -3058,6 +3061,17 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                return 1;
        }
 
+       nat_blocks = nat_segs << log_blocks_per_seg;
+       nat_bits_bytes = nat_blocks / BITS_PER_BYTE;
+       nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8);
+       if (__is_set_ckpt_flags(ckpt, CP_NAT_BITS_FLAG) &&
+               (cp_payload + F2FS_CP_PACKS +
+               NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) {
+               f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)",
+                         cp_payload, nat_bits_blocks);
+               return -EFSCORRUPTED;
+       }
+
        if (unlikely(f2fs_cp_error(sbi))) {
                f2fs_err(sbi, "A bug case: need to run fsck");
                return 1;