Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44a4bc97 authored by Theodore Ts'o's avatar Theodore Ts'o Committed by Greg Kroah-Hartman
Browse files

ext4: only look at the bg_flags field if it is valid

commit 8844618d8aa7a9973e7b527d038a2a589665002c upstream.

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: default avatarTheodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ac48bb9b
Loading
Loading
Loading
Loading
+10 −1
Original line number Original line Diff line number Diff line
@@ -451,7 +451,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
		goto verify;
		goto verify;
	}
	}
	ext4_lock_group(sb, block_group);
	ext4_lock_group(sb, block_group);
	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))) {
		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);
		err = ext4_init_block_bitmap(sb, bh, block_group, desc);
		set_bitmap_uptodate(bh);
		set_bitmap_uptodate(bh);
		set_buffer_uptodate(bh);
		set_buffer_uptodate(bh);
+12 −2
Original line number Original line Diff line number Diff line
@@ -155,7 +155,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
	}
	}


	ext4_lock_group(sb, block_group);
	ext4_lock_group(sb, block_group);
	if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
	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);
		memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
		ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
		ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
				     sb->s_blocksize * 8, bh->b_data);
				     sb->s_blocksize * 8, bh->b_data);
@@ -1000,7 +1009,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,


		/* recheck and clear flag under lock if we still need to */
		/* recheck and clear flag under lock if we still need to */
		ext4_lock_group(sb, group);
		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);
			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
			ext4_free_group_clusters_set(sb, gdp,
			ext4_free_group_clusters_set(sb, gdp,
				ext4_free_clusters_after_init(sb, group, gdp));
				ext4_free_clusters_after_init(sb, group, gdp));
+4 −2
Original line number Original line Diff line number Diff line
@@ -2456,7 +2456,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
	 * initialize bb_free to be able to skip
	 * initialize bb_free to be able to skip
	 * empty groups without initialization
	 * 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 =
		meta_group_info[i]->bb_free =
			ext4_free_clusters_after_init(sb, group, desc);
			ext4_free_clusters_after_init(sb, group, desc);
	} else {
	} else {
@@ -3023,7 +3024,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
#endif
#endif
	ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
	ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
		      ac->ac_b_ex.fe_len);
		      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);
		gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
		ext4_free_group_clusters_set(sb, gdp,
		ext4_free_group_clusters_set(sb, gdp,
					     ext4_free_clusters_after_init(sb,
					     ext4_free_clusters_after_init(sb,
+10 −1
Original line number Original line Diff line number Diff line
@@ -3095,13 +3095,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
	ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
	ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
	struct ext4_group_desc *gdp = NULL;
	struct ext4_group_desc *gdp = NULL;


	if (!ext4_has_group_desc_csum(sb))
		return ngroups;

	for (group = 0; group < ngroups; group++) {
	for (group = 0; group < ngroups; group++) {
		gdp = ext4_get_group_desc(sb, group, NULL);
		gdp = ext4_get_group_desc(sb, group, NULL);
		if (!gdp)
		if (!gdp)
			continue;
			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;
			break;
		ext4_error(sb, "Inode table for bg 0 marked as "
			   "needing zeroing");
		if (sb_rdonly(sb))
			return ngroups;
	}
	}


	return group;
	return group;