1 ext4: fix use-after-free race with debug_want_extra_isize
3 From: Barret Rhoden <brho@google.com>
5 When remounting with debug_want_extra_isize, we were not performing the
6 same checks that we do during a normal mount. That allowed us to set a
7 value for s_want_extra_isize that reached outside the s_inode_size.
9 Fixes: e2b911c53584 ("ext4: clean up feature test macros with predicate functions")
10 Reported-by: syzbot+f584efa0ac7213c226b7@syzkaller.appspotmail.com
11 Reviewed-by: Jan Kara <jack@suse.cz>
12 Signed-off-by: Barret Rhoden <brho@google.com>
13 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
14 Cc: stable@vger.kernel.org
19 Thanks for the review!
21 fs/ext4/super.c | 58 +++++++++++++++++++++++++++++--------------------
22 1 file changed, 34 insertions(+), 24 deletions(-)
24 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
25 index 6ed4eb81e674..184944d4d8d1 100644
28 @@ -3513,6 +3513,37 @@ int ext4_calculate_overhead(struct super_block *sb)
32 +static void ext4_clamp_want_extra_isize(struct super_block *sb)
34 + struct ext4_sb_info *sbi = EXT4_SB(sb);
35 + struct ext4_super_block *es = sbi->s_es;
37 + /* determine the minimum size of new large inodes, if present */
38 + if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
39 + sbi->s_want_extra_isize == 0) {
40 + sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
41 + EXT4_GOOD_OLD_INODE_SIZE;
42 + if (ext4_has_feature_extra_isize(sb)) {
43 + if (sbi->s_want_extra_isize <
44 + le16_to_cpu(es->s_want_extra_isize))
45 + sbi->s_want_extra_isize =
46 + le16_to_cpu(es->s_want_extra_isize);
47 + if (sbi->s_want_extra_isize <
48 + le16_to_cpu(es->s_min_extra_isize))
49 + sbi->s_want_extra_isize =
50 + le16_to_cpu(es->s_min_extra_isize);
53 + /* Check if enough inode space is available */
54 + if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
55 + sbi->s_inode_size) {
56 + sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
57 + EXT4_GOOD_OLD_INODE_SIZE;
58 + ext4_msg(sb, KERN_INFO,
59 + "required extra inode space not available");
63 static void ext4_set_resv_clusters(struct super_block *sb)
65 ext4_fsblk_t resv_clusters;
66 @@ -4387,30 +4418,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
70 - /* determine the minimum size of new large inodes, if present */
71 - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE &&
72 - sbi->s_want_extra_isize == 0) {
73 - sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
74 - EXT4_GOOD_OLD_INODE_SIZE;
75 - if (ext4_has_feature_extra_isize(sb)) {
76 - if (sbi->s_want_extra_isize <
77 - le16_to_cpu(es->s_want_extra_isize))
78 - sbi->s_want_extra_isize =
79 - le16_to_cpu(es->s_want_extra_isize);
80 - if (sbi->s_want_extra_isize <
81 - le16_to_cpu(es->s_min_extra_isize))
82 - sbi->s_want_extra_isize =
83 - le16_to_cpu(es->s_min_extra_isize);
86 - /* Check if enough inode space is available */
87 - if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
88 - sbi->s_inode_size) {
89 - sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
90 - EXT4_GOOD_OLD_INODE_SIZE;
91 - ext4_msg(sb, KERN_INFO, "required extra inode space not"
94 + ext4_clamp_want_extra_isize(sb);
96 ext4_set_resv_clusters(sb);
98 @@ -5194,6 +5202,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
102 + ext4_clamp_want_extra_isize(sb);
104 if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
105 test_opt(sb, JOURNAL_CHECKSUM)) {
106 ext4_msg(sb, KERN_ERR, "changing journal_checksum "
108 2.21.0.392.gf8f6787159e-goog