]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: verify s_desc_size is power-of-two value
authorAndreas Dilger <adilger@dilger.ca>
Mon, 23 Dec 2013 21:03:41 +0000 (16:03 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 23 Dec 2013 21:03:46 +0000 (16:03 -0500)
Add a LOG2_CHECK mode for check_super_value() so that it is easy
to verify values that are supposed to be power-of-two values
(s_desc_size and s_inode_size so far).  In ext2fs_check_desc()
also check for a power-of-two s_desc_size.

Print out s_desc_size in debugfs "stats" and dumpe2fs output, if
it is non-zero.

It turns out that the s_desc_size validation in check_super_block()
is not currently used by e2fsck, because the group descriptors are
verified earlier by ext2fs_check_desc(), and even without an
explicit check of s_desc_size the group descriptors fail to align
correctly on disk.  It makes sense to keep the check_super_block()
regardless, in case the code changes at some point in the future.

Signed-off-by: Andreas Dilger <adilger@dilger.ca>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
e2fsck/super.c
lib/e2p/ls.c
lib/ext2fs/check_desc.c
lib/ext2fs/closefs.c
lib/ext2fs/ext2_fs.h

index 56a338144b44f393d379d9c814122773c480cf89..b0cc440fbc0709c92597571f0bc734fd84f66ebf 100644 (file)
@@ -22,6 +22,7 @@
 
 #define MIN_CHECK 1
 #define MAX_CHECK 2
+#define LOG2_CHECK 4
 
 static void check_super_value(e2fsck_t ctx, const char *descr,
                              unsigned long value, int flags,
@@ -30,7 +31,8 @@ static void check_super_value(e2fsck_t ctx, const char *descr,
        struct          problem_context pctx;
 
        if (((flags & MIN_CHECK) && (value < min_val)) ||
-           ((flags & MAX_CHECK) && (value > max_val))) {
+           ((flags & MAX_CHECK) && (value > max_val)) ||
+           ((flags & LOG2_CHECK) && (value & (value - 1) != 0))) {
                clear_problem_context(&pctx);
                pctx.num = value;
                pctx.str = descr;
@@ -527,14 +529,17 @@ void check_super_block(e2fsck_t ctx)
                          MAX_CHECK, 0, ext2fs_blocks_count(sb) / 2);
        check_super_value(ctx, "reserved_gdt_blocks",
                          sb->s_reserved_gdt_blocks, MAX_CHECK, 0,
-                         fs->blocksize/4);
+                         fs->blocksize / sizeof(__u32));
+       check_super_value(ctx, "desc_size",
+                         sb->s_desc_size, MAX_CHECK | LOG2_CHECK, 0,
+                         EXT2_MAX_DESC_SIZE);
        if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
                check_super_value(ctx, "first_ino", sb->s_first_ino,
                                  MIN_CHECK | MAX_CHECK,
                                  EXT2_GOOD_OLD_FIRST_INO, sb->s_inodes_count);
        inode_size = EXT2_INODE_SIZE(sb);
        check_super_value(ctx, "inode_size",
-                         inode_size, MIN_CHECK | MAX_CHECK,
+                         inode_size, MIN_CHECK | MAX_CHECK | LOG2_CHECK,
                          EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize);
        if (sb->s_blocks_per_group != (sb->s_clusters_per_group *
                                       EXT2FS_CLUSTER_RATIO(fs))) {
@@ -544,13 +549,6 @@ void check_super_block(e2fsck_t ctx)
                ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
                return;
        }
-       if (inode_size & (inode_size - 1)) {
-               pctx.num = inode_size;
-               pctx.str = "inode_size";
-               fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
-               ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
-               return;
-       }
 
        if ((ctx->flags & E2F_FLAG_GOT_DEVSIZE) &&
            (ctx->num_blocks < ext2fs_blocks_count(sb))) {
index f05e16dccc8e450dd4035f113926019164fdf0c1..5b3d3c8b7b17145efca07e2fa359b713d3476f9d 100644 (file)
@@ -259,6 +259,8 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
        else
                fprintf(f, "Fragment size:            %u\n",
                        EXT2_CLUSTER_SIZE(sb));
+       if (sb->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
+               fprintf(f, "Group descriptor size:    %u\n", sb->s_desc_size);
        if (sb->s_reserved_gdt_blocks)
                fprintf(f, "Reserved GDT blocks:      %u\n",
                        sb->s_reserved_gdt_blocks);
index a6fcc454b4fed96e99b85474aeb7a8f5e797dbbf..1a768f92e9b1491be10e86b6fa935d0ebac83d4e 100644 (file)
@@ -42,6 +42,9 @@ errcode_t ext2fs_check_desc(ext2_filsys fs)
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+       if (EXT2_DESC_SIZE(fs->super) & (EXT2_DESC_SIZE(fs->super) - 1))
+               return EXT2_ET_BAD_DESC_SIZE;
+
        retval = ext2fs_allocate_subcluster_bitmap(fs, "check_desc map", &bmap);
        if (retval)
                return retval;
index 3a804240c0074e40bbc8fda0df4b67088920d30b..3e4af7f9a0b971663dc3401daa73e910bf3718df 100644 (file)
@@ -302,7 +302,7 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
               fs->desc_blocks);
 
        /* swap the group descriptors */
-       for (j=0; j < fs->group_desc_count; j++) {
+       for (j = 0; j < fs->group_desc_count; j++) {
                gdp = ext2fs_group_desc(fs, group_shadow, j);
                ext2fs_swap_group_desc2(fs, gdp);
        }
index fb3f7cc3cc96ae215ab4daaae8fbd64a7c7c7f25..930c2a3f5c5a37e7d70eb7d0f92c62b8b25109e4 100644 (file)
@@ -159,7 +159,7 @@ struct ext2_group_desc
        __u16   bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
        __u16   bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
        __u16   bg_itable_unused;       /* Unused inodes count */
-       __u16   bg_checksum;            /* crc16(s_uuid+grouo_num+group_desc)*/
+       __u16   bg_checksum;            /* crc16(s_uuid+group_num+group_desc)*/
 };
 
 /*