]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ext4: only look at the bg_flags field if it is valid
authorTheodore Ts'o <tytso@mit.edu>
Thu, 14 Jun 2018 04:58:00 +0000 (00:58 -0400)
committerBrian Maly <brian.maly@oracle.com>
Tue, 5 Mar 2019 20:58:35 +0000 (15:58 -0500)
The bg_flags field in the block group descripts is only valid if the
uninit_bg or metadata_csum feature is enabled.  We were not
consistently looking at this field; fix this.

Also block group #0 must never have uninitialized allocation bitmaps,
or need to be zeroed, since that's where the root inode, and other
special inodes are set up.  Check for these conditions and mark the
file system as corrupted if they are detected.

This addresses CVE-2018-10876.

https://bugzilla.kernel.org/show_bug.cgi?id=199403

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
(cherry picked from commit 8844618d8aa7a9973e7b527d038a2a589665002c)

Orabug: 29316684
CVE: CVE-2018-10876.

Signed-off-by: John Donnelly <John.P.Donnelly@oracle.com>
Reviewed-by: Allen Pais <allen.pais@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
Conflicts:
fs/ext4/balloc.c
fs/ext4/ialloc.c

Signed-off-by: Brian Maly <brian.maly@oracle.com>
fs/ext4/balloc.c
fs/ext4/ialloc.c
fs/ext4/mballoc.c
fs/ext4/super.c

index 9f08f2a8e87e64248f9a38238f5e0bd61a73296d..b0fdb9b195969935adf2a02ba2c2c5f571d87b2c 100644 (file)
@@ -420,6 +420,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct buffer_head *bh;
        ext4_fsblk_t bitmap_blk;
+       int err;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
        if (!desc)
@@ -448,9 +449,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
                goto verify;
        }
        ext4_lock_group(sb, block_group);
-       if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-               int err;
-
+       if (ext4_has_group_desc_csum(sb) &&
+           (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
+               if (block_group == 0) {
+                       ext4_unlock_group(sb, block_group);
+                       unlock_buffer(bh);
+                       ext4_error(sb, "Block bitmap for bg 0 marked "
+                                  "uninitialized");
+                       err = -EFSCORRUPTED;
+                       goto out;
+               }
                err = ext4_init_block_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
@@ -483,6 +491,7 @@ verify:
        ext4_validate_block_bitmap(sb, desc, block_group, bh);
        if (buffer_verified(bh))
                return bh;
+out:
        put_bh(bh);
        return NULL;
 }
index 3cb8be756e23fc4b158f78e50b42db669f32ccae..d0afdae08cb778ad560ded080b2c7b42f8e88090 100644 (file)
@@ -126,6 +126,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
        ext4_fsblk_t bitmap_blk;
        struct ext4_group_info *grp;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
+       int err = 0;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
        if (!desc)
@@ -155,8 +156,19 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
        }
 
        ext4_lock_group(sb, block_group);
-       if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-               ext4_init_inode_bitmap(sb, bh, block_group, desc);
+       if (ext4_has_group_desc_csum(sb) &&
+           (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) {
+               if (block_group == 0) {
+                       ext4_unlock_group(sb, block_group);
+                       unlock_buffer(bh);
+                       ext4_error(sb, "Inode bitmap for bg 0 marked "
+                                  "uninitialized");
+                       err = -EFSCORRUPTED;
+                       goto out;
+               }
+               memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
+               ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
+                                    sb->s_blocksize * 8, bh->b_data);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
                set_buffer_verified(bh);
@@ -213,6 +225,9 @@ verify:
        ext4_unlock_group(sb, block_group);
        set_buffer_verified(bh);
        return bh;
+out:
+       put_bh(bh);
+       return ERR_PTR(err);
 }
 
 /*
@@ -909,7 +924,8 @@ got:
 
                /* recheck and clear flag under lock if we still need to */
                ext4_lock_group(sb, group);
-               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+               if (ext4_has_group_desc_csum(sb) &&
+                   (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
                        gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
                        ext4_free_group_clusters_set(sb, gdp,
                                ext4_free_clusters_after_init(sb, group, gdp));
index 0eba2331ca479ffca78f86482f80a9bc80b88dc9..a9cdaef7938ce8f4f0577cce9f81440ea83dd8f5 100644 (file)
@@ -2411,7 +2411,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
         * initialize bb_free to be able to skip
         * empty groups without initialization
         */
-       if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+       if (ext4_has_group_desc_csum(sb) &&
+           (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
                meta_group_info[i]->bb_free =
                        ext4_free_clusters_after_init(sb, group, desc);
        } else {
@@ -2935,7 +2936,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
 #endif
        ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
                      ac->ac_b_ex.fe_len);
-       if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+       if (ext4_has_group_desc_csum(sb) &&
+           (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
                gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
                ext4_free_group_clusters_set(sb, gdp,
                                             ext4_free_clusters_after_init(sb,
index e3e45120fb39d2d48f5f3e827b8a909de28435d5..3589eae580d8751c919e0f0906cc108a5c3c5ee6 100644 (file)
@@ -3160,13 +3160,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
        ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
        struct ext4_group_desc *gdp = NULL;
 
+       if (!ext4_has_group_desc_csum(sb))
+               return ngroups;
+
        for (group = 0; group < ngroups; group++) {
                gdp = ext4_get_group_desc(sb, group, NULL);
                if (!gdp)
                        continue;
 
-               if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
+               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
+                       continue;
+               if (group != 0)
                        break;
+               ext4_error(sb, "Inode table for bg 0 marked as "
+                          "needing zeroing");
+               if (sb_rdonly(sb))
+                       return ngroups;
        }
 
        return group;