]>
Commit | Line | Data |
---|---|---|
21f93658 GKH |
1 | From 7bc04c5c2cc467c5b40f2b03ba08da174a0d5fa7 Mon Sep 17 00:00:00 2001 |
2 | From: Barret Rhoden <brho@google.com> | |
3 | Date: Thu, 25 Apr 2019 11:55:50 -0400 | |
4 | Subject: ext4: fix use-after-free race with debug_want_extra_isize | |
5 | ||
6 | From: Barret Rhoden <brho@google.com> | |
7 | ||
8 | commit 7bc04c5c2cc467c5b40f2b03ba08da174a0d5fa7 upstream. | |
9 | ||
10 | When remounting with debug_want_extra_isize, we were not performing the | |
11 | same checks that we do during a normal mount. That allowed us to set a | |
12 | value for s_want_extra_isize that reached outside the s_inode_size. | |
13 | ||
14 | Fixes: e2b911c53584 ("ext4: clean up feature test macros with predicate functions") | |
15 | Reported-by: syzbot+f584efa0ac7213c226b7@syzkaller.appspotmail.com | |
16 | Reviewed-by: Jan Kara <jack@suse.cz> | |
17 | Signed-off-by: Barret Rhoden <brho@google.com> | |
18 | Signed-off-by: Theodore Ts'o <tytso@mit.edu> | |
19 | Cc: stable@vger.kernel.org | |
20 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
21 | ||
22 | --- | |
23 | fs/ext4/super.c | 58 ++++++++++++++++++++++++++++++++------------------------ | |
24 | 1 file changed, 34 insertions(+), 24 deletions(-) | |
25 | ||
26 | --- a/fs/ext4/super.c | |
27 | +++ b/fs/ext4/super.c | |
28 | @@ -3514,6 +3514,37 @@ int ext4_calculate_overhead(struct super | |
29 | return 0; | |
30 | } | |
31 | ||
32 | +static void ext4_clamp_want_extra_isize(struct super_block *sb) | |
33 | +{ | |
34 | + struct ext4_sb_info *sbi = EXT4_SB(sb); | |
35 | + struct ext4_super_block *es = sbi->s_es; | |
36 | + | |
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); | |
51 | + } | |
52 | + } | |
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"); | |
60 | + } | |
61 | +} | |
62 | + | |
63 | static void ext4_set_resv_clusters(struct super_block *sb) | |
64 | { | |
65 | ext4_fsblk_t resv_clusters; | |
66 | @@ -4388,30 +4419,7 @@ no_journal: | |
67 | } else if (ret) | |
68 | goto failed_mount4a; | |
69 | ||
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); | |
84 | - } | |
85 | - } | |
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" | |
92 | - "available"); | |
93 | - } | |
94 | + ext4_clamp_want_extra_isize(sb); | |
95 | ||
96 | ext4_set_resv_clusters(sb); | |
97 | ||
98 | @@ -5195,6 +5203,8 @@ static int ext4_remount(struct super_blo | |
99 | goto restore_opts; | |
100 | } | |
101 | ||
102 | + ext4_clamp_want_extra_isize(sb); | |
103 | + | |
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 " |