1 ext4: only look at the bg_flags field if it is valid
3 The bg_flags field in the block group descripts is only valid if the
4 uninit_bg or metadata_csum feature is enabled. We were not
5 consistently looking at this field; fix this.
7 Also block group #0 must never have uninitialized allocation bitmaps,
8 or need to be zeroed, since that's where the root inode, and other
9 special inodes are set up. Check for these conditions and mark the
10 file system as corrupted if they are detected.
12 This addresses CVE-2018-10876.
14 https://bugzilla.kernel.org/show_bug.cgi?id=199403
16 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
18 fs/ext4/balloc.c | 11 ++++++++++-
19 fs/ext4/ialloc.c | 14 ++++++++++++--
20 fs/ext4/mballoc.c | 6 ++++--
21 fs/ext4/super.c | 11 ++++++++++-
22 4 files changed, 36 insertions(+), 6 deletions(-)
24 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
25 index 8a2e202ade8a..e68cefe08261 100644
26 --- a/fs/ext4/balloc.c
27 +++ b/fs/ext4/balloc.c
28 @@ -438,7 +438,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
31 ext4_lock_group(sb, block_group);
32 - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
33 + if (ext4_has_group_desc_csum(sb) &&
34 + (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
35 + if (block_group == 0) {
36 + ext4_unlock_group(sb, block_group);
38 + ext4_error(sb, "Block bitmap for bg 0 marked "
40 + err = -EFSCORRUPTED;
43 err = ext4_init_block_bitmap(sb, bh, block_group, desc);
44 set_bitmap_uptodate(bh);
45 set_buffer_uptodate(bh);
46 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
47 index 4d6e007f3569..da6c10c1e37a 100644
48 --- a/fs/ext4/ialloc.c
49 +++ b/fs/ext4/ialloc.c
50 @@ -150,7 +150,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
53 ext4_lock_group(sb, block_group);
54 - if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
55 + if (ext4_has_group_desc_csum(sb) &&
56 + (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) {
57 + if (block_group == 0) {
58 + ext4_unlock_group(sb, block_group);
60 + ext4_error(sb, "Inode bitmap for bg 0 marked "
62 + err = -EFSCORRUPTED;
65 memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
66 ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
67 sb->s_blocksize * 8, bh->b_data);
68 @@ -994,7 +1003,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
70 /* recheck and clear flag under lock if we still need to */
71 ext4_lock_group(sb, group);
72 - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
73 + if (ext4_has_group_desc_csum(sb) &&
74 + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
75 gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
76 ext4_free_group_clusters_set(sb, gdp,
77 ext4_free_clusters_after_init(sb, group, gdp));
78 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
79 index 243c42fdc155..402c769c51ea 100644
80 --- a/fs/ext4/mballoc.c
81 +++ b/fs/ext4/mballoc.c
82 @@ -2444,7 +2444,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
83 * initialize bb_free to be able to skip
84 * empty groups without initialization
86 - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
87 + if (ext4_has_group_desc_csum(sb) &&
88 + (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
89 meta_group_info[i]->bb_free =
90 ext4_free_clusters_after_init(sb, group, desc);
92 @@ -3010,7 +3011,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
94 ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
96 - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
97 + if (ext4_has_group_desc_csum(sb) &&
98 + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
99 gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
100 ext4_free_group_clusters_set(sb, gdp,
101 ext4_free_clusters_after_init(sb,
102 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
103 index c61675d62195..4d34430d75f6 100644
104 --- a/fs/ext4/super.c
105 +++ b/fs/ext4/super.c
106 @@ -3139,13 +3139,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
107 ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
108 struct ext4_group_desc *gdp = NULL;
110 + if (!ext4_has_group_desc_csum(sb))
113 for (group = 0; group < ngroups; group++) {
114 gdp = ext4_get_group_desc(sb, group, NULL);
118 - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
119 + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
123 + ext4_error(sb, "Inode table for bg 0 marked as "
124 + "needing zeroing");