OSDN Git Service

Make ext2fs_check_desc() more stringent to force use of backup superbocks
authorTheodore Ts'o <tytso@mit.edu>
Thu, 10 Jul 2008 20:35:05 +0000 (16:35 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 10 Jul 2008 21:25:33 +0000 (17:25 -0400)
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" <tytso@mit.edu>
lib/ext2fs/alloc_sb.c
lib/ext2fs/check_desc.c
tests/f_resize_inode/expect

index 200ce5c..cdcb866 100644 (file)
@@ -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);
index 900b179..c84589b 100644 (file)
  */
 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;
 }
index 8e96059..bd45575 100644 (file)
@@ -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 <device>
+../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