1 ext4: fix in-superblock mount options processing
3 Fix a large number of problems with how we handle mount options in the
4 superblock. For one, if the string in the superblock is long enough
5 that it is not null terminated, we could run off the end of the string
6 and try to interpret superblocks fields as characters. It's unlikely
7 this will cause a security problem, but it could result in an invalid
8 parse. Also, parse_options is destructive to the string, so in some
9 cases if there is a comma-separated string, it would be modified in
10 the superblock. (Fortunately it only happens on file systems with a
13 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
14 Cc: stable@vger.kernel.org
16 fs/ext4/super.c | 38 +++++++++++++++++++++++---------------
17 1 file changed, 23 insertions(+), 15 deletions(-)
19 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
20 index 0f9ae4ce33d6..404e6f3c1bed 100644
23 @@ -3303,7 +3303,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
24 char *orig_data = kstrdup(data, GFP_KERNEL);
25 struct buffer_head *bh;
26 struct ext4_super_block *es = NULL;
27 - struct ext4_sb_info *sbi;
28 + struct ext4_sb_info *sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
30 ext4_fsblk_t sb_block = get_sb_block(&data);
31 ext4_fsblk_t logical_sb_block;
32 @@ -3322,16 +3322,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
33 unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
34 ext4_group_t first_not_zeroed;
36 - sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
39 + if ((data && !orig_data) || !sbi)
42 sbi->s_blockgroup_lock =
43 kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
44 - if (!sbi->s_blockgroup_lock) {
48 + if (!sbi->s_blockgroup_lock)
53 sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
54 @@ -3477,11 +3475,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
56 sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
58 - if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
59 - &journal_devnum, &journal_ioprio, 0)) {
60 - ext4_msg(sb, KERN_WARNING,
61 - "failed to parse options in superblock: %s",
62 - sbi->s_es->s_mount_opts);
63 + if (sbi->s_es->s_mount_opts[0]) {
64 + char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts,
65 + sizeof(sbi->s_es->s_mount_opts),
69 + if (!parse_options(s_mount_opts, sb, &journal_devnum,
70 + &journal_ioprio, 0)) {
71 + ext4_msg(sb, KERN_WARNING,
72 + "failed to parse options in superblock: %s",
75 + kfree(s_mount_opts);
77 sbi->s_def_mount_opt = sbi->s_mount_opt;
78 if (!parse_options((char *) data, sb, &journal_devnum,
79 @@ -4162,7 +4168,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
81 if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
82 ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
83 - "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
84 + "Opts: %.*s%s%s", descr,
85 + (int) sizeof(sbi->s_es->s_mount_opts),
86 + sbi->s_es->s_mount_opts,
87 *sbi->s_es->s_mount_opts ? "; " : "", orig_data);
89 if (es->s_error_count)
90 @@ -4241,8 +4249,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
93 kfree(sbi->s_blockgroup_lock);
98 return err ? err : ret;