]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
libext2fs: calculate and verify superblock checksums
authorDarrick J. Wong <djwong@us.ibm.com>
Fri, 3 Aug 2012 00:47:44 +0000 (20:47 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 3 Aug 2012 00:47:44 +0000 (20:47 -0400)
Calculate and verify the superblock checksums.  Each copy of the
superblock records the number of the group it's in and the FS UUID, so
we can simply checksum the whole block.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
lib/ext2fs/closefs.c
lib/ext2fs/csum.c
lib/ext2fs/ext2_err.et.in
lib/ext2fs/ext2fs.h
lib/ext2fs/openfs.c

index b01e42ee5ac10782248a2ab10500299f6bf9b736..22cecb61231af2b52759b905d05a802b231a3381 100644 (file)
@@ -246,15 +246,19 @@ static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
                                    blk_t group_block,
                                    struct ext2_super_block *super_shadow)
 {
+       errcode_t retval;
        dgrp_t  sgrp = group;
 
        if (sgrp > ((1 << 16) - 1))
                sgrp = (1 << 16) - 1;
+
+       super_shadow->s_block_group_nr = sgrp;
 #ifdef WORDS_BIGENDIAN
-       super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
-#else
-       fs->super->s_block_group_nr = sgrp;
+       ext2fs_swap_super(super_shadow);
 #endif
+       retval = ext2fs_superblock_csum_set(fs, super_shadow);
+       if (retval)
+               return retval;
 
        return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE,
                                    super_shadow);
@@ -314,6 +318,7 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
                                  &group_shadow);
        if (retval)
                goto errout;
+       memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block));
        memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize *
               fs->desc_blocks);
 
@@ -334,10 +339,6 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
         */
        fs->super->s_state &= ~EXT2_VALID_FS;
        fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
-#ifdef WORDS_BIGENDIAN
-       *super_shadow = *fs->super;
-       ext2fs_swap_super(super_shadow);
-#endif
 
        /*
         * If this is an external journal device, don't write out the
@@ -415,6 +416,10 @@ write_primary_superblock_only:
        ext2fs_swap_super(super_shadow);
 #endif
 
+       retval = ext2fs_superblock_csum_set(fs, super_shadow);
+       if (retval)
+               return retval;
+
        if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC))
                retval = io_channel_flush(fs->io);
        retval = write_primary_superblock(fs, super_shadow);
index 8325fb54b1c11c319277a488e31a88855aaaa8d7..4cb242b9a78e5e91445d26164049c4b3e756e9f8 100644 (file)
 #define STATIC static
 #endif
 
+static __u32 ext2fs_superblock_csum(ext2_filsys fs, struct ext2_super_block *sb)
+{
+       int offset = offsetof(struct ext2_super_block, s_checksum);
+
+       return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset);
+}
+
+int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb)
+{
+       __u32 calculated;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       calculated = ext2fs_superblock_csum(fs, sb);
+
+       return ext2fs_le32_to_cpu(sb->s_checksum) == calculated;
+}
+
+errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
+                                    struct ext2_super_block *sb)
+{
+       __u32 crc;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       crc = ext2fs_superblock_csum(fs, sb);
+       sb->s_checksum = ext2fs_cpu_to_le32(crc);
+
+       return 0;
+}
+
 static errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs, ext2_ino_t inum,
                                            blk64_t block,
                                            struct ext2_ext_attr_header *hdr,
index 90be193f4c256560e80d4c684198be62d887a2dd..0580865830df2f42c5a2b76f4434ef7a4845ec47 100644 (file)
@@ -464,4 +464,7 @@ ec  EXT2_ET_DIR_CSUM_INVALID,
 ec     EXT2_ET_EXT_ATTR_CSUM_INVALID,
        "Extended attribute block checksum does not match block"
 
+ec     EXT2_ET_SB_CSUM_INVALID,
+       "Superblock checksum does not match superblock"
+
        end
index b793885163dcb681e7f4141a14e4fcbe1fdd8efb..a6fc7f31e1a1f614aa7430340c5e12163b619d74 100644 (file)
@@ -943,6 +943,10 @@ extern __u32 ext2fs_crc32c_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
+                                           struct ext2_super_block *sb);
+extern int ext2fs_superblock_csum_verify(ext2_filsys fs,
+                                        struct ext2_super_block *sb);
 extern errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs,
                                        ext2_ino_t inum, blk64_t block,
                                        struct ext2_ext_attr_header *hdr);
index 3675518f3890a31b376a609e47248d37188512a1..2a5c2351345fa6204743c1a02942505422b936bf 100644 (file)
@@ -195,6 +195,12 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
        if (fs->orig_super)
                memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
 
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !ext2fs_superblock_csum_verify(fs, fs->super)) {
+               retval = EXT2_ET_SB_CSUM_INVALID;
+               goto cleanup;
+       }
+
 #ifdef WORDS_BIGENDIAN
        fs->flags |= EXT2_FLAG_SWAP_BYTES;
        ext2fs_swap_super(fs->super);