From: Theodore Ts'o Date: Thu, 10 Jul 2008 20:35:05 +0000 (-0400) Subject: Make ext2fs_check_desc() more stringent to force use of backup superbocks X-Git-Tag: v1.41.0~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=009c02baf90a55b4b2d9c9e3d0a4cfc3e2531640;p=thirdparty%2Fe2fsprogs.git Make ext2fs_check_desc() more stringent to force use of backup superbocks E2fsck could to do more damage to a filesystem by trying to relocate inode tables due to corrupted block group descriptors, and the relocation could seriously damage the filesystem. This patch enhances ext2fs_check_desk() so it detects more self-inconsistent block group descriptors, including the cases where e2sck might be tempted to relocate the inode table, and reports the block group descriptors as invalid; this will cause e2fsck to attempt to use the backup superblocks, which hopefully have not been trashed. Addresses-Sourceforge-Bug: #1840291 Signed-off-by: "Theodore Ts'o" --- diff --git a/lib/ext2fs/alloc_sb.c b/lib/ext2fs/alloc_sb.c index 200ce5cf2..cdcb8666b 100644 --- a/lib/ext2fs/alloc_sb.c +++ b/lib/ext2fs/alloc_sb.c @@ -63,7 +63,9 @@ int ext2fs_reserve_super_and_bgd(ext2_filsys fs, if (fs->super->s_reserved_gdt_blocks && fs->block_map == bmap) fs->group_desc[group].bg_flags &= ~EXT2_BG_BLOCK_UNINIT; for (j=0; j < old_desc_blocks; j++) - ext2fs_mark_block_bitmap(bmap, old_desc_blk + j); + if (old_desc_blk + j < fs->super->s_blocks_count) + ext2fs_mark_block_bitmap(bmap, + old_desc_blk + j); } if (new_desc_blk) ext2fs_mark_block_bitmap(bmap, new_desc_blk); diff --git a/lib/ext2fs/check_desc.c b/lib/ext2fs/check_desc.c index 900b17902..c84589bf0 100644 --- a/lib/ext2fs/check_desc.c +++ b/lib/ext2fs/check_desc.c @@ -31,41 +31,73 @@ */ errcode_t ext2fs_check_desc(ext2_filsys fs) { + ext2fs_block_bitmap bmap; + errcode_t retval; dgrp_t i; blk_t first_block = fs->super->s_first_data_block; blk_t last_block = fs->super->s_blocks_count-1; + blk_t blk, b; + int j; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + retval = ext2fs_allocate_block_bitmap(fs, "check_desc map", &bmap); + if (retval) + return retval; + + for (i = 0; i < fs->group_desc_count; i++) + ext2fs_reserve_super_and_bgd(fs, i, bmap); + for (i = 0; i < fs->group_desc_count; i++) { if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { first_block = ext2fs_group_first_block(fs, i); last_block = ext2fs_group_last_block(fs, i); + if (i == (fs->group_desc_count - 1)) + last_block = fs->super->s_blocks_count-1; } /* - * Check to make sure block bitmap for group is - * located within the group. + * Check to make sure the block bitmap for group is sane */ - if (fs->group_desc[i].bg_block_bitmap < first_block || - fs->group_desc[i].bg_block_bitmap > last_block) - return EXT2_ET_GDESC_BAD_BLOCK_MAP; + blk = fs->group_desc[i].bg_block_bitmap; + if (blk < first_block || blk > last_block || + ext2fs_test_block_bitmap(bmap, blk)) { + retval = EXT2_ET_GDESC_BAD_BLOCK_MAP; + goto errout; + } + ext2fs_mark_block_bitmap(bmap, blk); + /* - * Check to make sure inode bitmap for group is - * located within the group + * Check to make sure the inode bitmap for group is sane */ - if (fs->group_desc[i].bg_inode_bitmap < first_block || - fs->group_desc[i].bg_inode_bitmap > last_block) - return EXT2_ET_GDESC_BAD_INODE_MAP; + blk = fs->group_desc[i].bg_inode_bitmap; + if (blk < first_block || blk > last_block || + ext2fs_test_block_bitmap(bmap, blk)) { + retval = EXT2_ET_GDESC_BAD_INODE_MAP; + goto errout; + } + ext2fs_mark_block_bitmap(bmap, blk); + /* - * Check to make sure inode table for group is located - * within the group + * Check to make sure the inode table for group is sane */ - if (fs->group_desc[i].bg_inode_table < first_block || - ((fs->group_desc[i].bg_inode_table + - fs->inode_blocks_per_group - 1) > last_block)) - return EXT2_ET_GDESC_BAD_INODE_TABLE; + blk = fs->group_desc[i].bg_inode_table; + if (blk < first_block || + ((blk + fs->inode_blocks_per_group - 1) > last_block)) { + retval = EXT2_ET_GDESC_BAD_INODE_TABLE; + goto errout; + } + for (j = 0, b = blk; j < fs->inode_blocks_per_group; + j++, b++) { + if (ext2fs_test_block_bitmap(bmap, b)) { + retval = EXT2_ET_GDESC_BAD_INODE_TABLE; + goto errout; + } + ext2fs_mark_block_bitmap(bmap, b); + } } - return 0; +errout: + ext2fs_free_block_bitmap(bmap); + return retval; } diff --git a/tests/f_resize_inode/expect b/tests/f_resize_inode/expect index 8e96059de..bd45575a4 100644 --- a/tests/f_resize_inode/expect +++ b/tests/f_resize_inode/expect @@ -111,15 +111,16 @@ Exit status is 0 debugfs -R ''set_super_value reserved_gdt_blocks 15679'' -w ./test.img Exit status is 0 -Corruption found in superblock. (reserved_gdt_blocks = 15679). - -The superblock could not be read or does not describe a correct ext2 -filesystem. If the device is valid and it really contains an ext2 -filesystem (and not swap or ufs or something else), then the superblock -is corrupt, and you might try running e2fsck with an alternate superblock: - e2fsck -b 1025 +../e2fsck/e2fsck: Group descriptors look bad... trying backup blocks... +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information -Exit status is 8 +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 11/4096 files (0.0% non-contiguous), 2107/16384 blocks +Exit status is 1 ----------------------------------------------- debugfs -R ''set_super_value reserved_gdt_blocks 32'' -w ./test.img