ext4: only look at the bg_flags field if it is valid
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
This commit is contained in:
parent
77260807d1
commit
8844618d8a
4 changed files with 36 additions and 6 deletions
|
@ -438,7 +438,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)) {
|
||||
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);
|
||||
|
|
|
@ -150,7 +150,16 @@ 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)) {
|
||||
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);
|
||||
|
@ -994,7 +1003,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
|
|||
|
||||
/* 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));
|
||||
|
|
|
@ -2444,7 +2444,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 {
|
||||
|
@ -3010,7 +3011,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,
|
||||
|
|
|
@ -3139,13 +3139,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;
|
||||
|
|
Loading…
Reference in a new issue