Check in ext4 hardening bug fixes
[ext4-patch-queue.git] / only-look-at-bg_flags-if-valid
blob6b6f35002e41a8031cbc23b33697528dd333b19f
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 https://bugzilla.kernel.org/show_bug.cgi?id=199403
14 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
15 ---
16  fs/ext4/balloc.c  | 11 ++++++++++-
17  fs/ext4/ialloc.c  | 14 ++++++++++++--
18  fs/ext4/mballoc.c |  6 ++++--
19  fs/ext4/super.c   | 11 ++++++++++-
20  4 files changed, 36 insertions(+), 6 deletions(-)
22 diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
23 index 8a2e202ade8a..e68cefe08261 100644
24 --- a/fs/ext4/balloc.c
25 +++ b/fs/ext4/balloc.c
26 @@ -438,7 +438,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
27                 goto verify;
28         }
29         ext4_lock_group(sb, block_group);
30 -       if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
31 +       if (ext4_has_group_desc_csum(sb) &&
32 +           (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
33 +               if (block_group == 0) {
34 +                       ext4_unlock_group(sb, block_group);
35 +                       unlock_buffer(bh);
36 +                       ext4_error(sb, "Block bitmap for bg 0 marked "
37 +                                  "uninitialized");
38 +                       err = -EFSCORRUPTED;
39 +                       goto out;
40 +               }
41                 err = ext4_init_block_bitmap(sb, bh, block_group, desc);
42                 set_bitmap_uptodate(bh);
43                 set_buffer_uptodate(bh);
44 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
45 index 4d6e007f3569..da6c10c1e37a 100644
46 --- a/fs/ext4/ialloc.c
47 +++ b/fs/ext4/ialloc.c
48 @@ -150,7 +150,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
49         }
51         ext4_lock_group(sb, block_group);
52 -       if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
53 +       if (ext4_has_group_desc_csum(sb) &&
54 +           (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) {
55 +               if (block_group == 0) {
56 +                       ext4_unlock_group(sb, block_group);
57 +                       unlock_buffer(bh);
58 +                       ext4_error(sb, "Inode bitmap for bg 0 marked "
59 +                                  "uninitialized");
60 +                       err = -EFSCORRUPTED;
61 +                       goto out;
62 +               }
63                 memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
64                 ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
65                                      sb->s_blocksize * 8, bh->b_data);
66 @@ -994,7 +1003,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
68                 /* recheck and clear flag under lock if we still need to */
69                 ext4_lock_group(sb, group);
70 -               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
71 +               if (ext4_has_group_desc_csum(sb) &&
72 +                   (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
73                         gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
74                         ext4_free_group_clusters_set(sb, gdp,
75                                 ext4_free_clusters_after_init(sb, group, gdp));
76 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
77 index 243c42fdc155..402c769c51ea 100644
78 --- a/fs/ext4/mballoc.c
79 +++ b/fs/ext4/mballoc.c
80 @@ -2444,7 +2444,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
81          * initialize bb_free to be able to skip
82          * empty groups without initialization
83          */
84 -       if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
85 +       if (ext4_has_group_desc_csum(sb) &&
86 +           (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
87                 meta_group_info[i]->bb_free =
88                         ext4_free_clusters_after_init(sb, group, desc);
89         } else {
90 @@ -3010,7 +3011,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
91  #endif
92         ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start,
93                       ac->ac_b_ex.fe_len);
94 -       if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
95 +       if (ext4_has_group_desc_csum(sb) &&
96 +           (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
97                 gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
98                 ext4_free_group_clusters_set(sb, gdp,
99                                              ext4_free_clusters_after_init(sb,
100 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
101 index c61675d62195..4d34430d75f6 100644
102 --- a/fs/ext4/super.c
103 +++ b/fs/ext4/super.c
104 @@ -3139,13 +3139,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
105         ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
106         struct ext4_group_desc *gdp = NULL;
108 +       if (!ext4_has_group_desc_csum(sb))
109 +               return ngroups;
111         for (group = 0; group < ngroups; group++) {
112                 gdp = ext4_get_group_desc(sb, group, NULL);
113                 if (!gdp)
114                         continue;
116 -               if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
117 +               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
118 +                       continue;
119 +               if (group != 0)
120                         break;
121 +               ext4_error(sb, "Inode table for bg 0 marked as "
122 +                          "needing zeroing");
123 +               if (sb_rdonly(sb))
124 +                       return ngroups;
125         }
127         return group;