add patch forbid-i_extra_isize-not-divisible-by-4
[ext4-patch-queue.git] / fix-sb-mount-options-processing
blob46112817affb79114f7c19beecd038a61081d842
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
11 1k block size.)
13 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
14 Cc: stable@vger.kernel.org
15 ---
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
21 --- a/fs/ext4/super.c
22 +++ b/fs/ext4/super.c
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);
29         ext4_fsblk_t block;
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);
37 -       if (!sbi)
38 -               goto out_free_orig;
39 +       if ((data && !orig_data) || !sbi)
40 +               goto out_free_base;
42         sbi->s_blockgroup_lock =
43                 kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
44 -       if (!sbi->s_blockgroup_lock) {
45 -               kfree(sbi);
46 -               goto out_free_orig;
47 -       }
48 +       if (!sbi->s_blockgroup_lock)
49 +               goto out_free_base;
51         sb->s_fs_info = sbi;
52         sbi->s_sb = sb;
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)
55          */
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),
66 +                                             GFP_KERNEL);
67 +               if (!s_mount_opts)
68 +                       goto failed_mount;
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",
73 +                                s_mount_opts);
74 +               }
75 +               kfree(s_mount_opts);
76         }
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)
91  out_fail:
92         sb->s_fs_info = NULL;
93         kfree(sbi->s_blockgroup_lock);
94 +out_free_base:
95         kfree(sbi);
96 -out_free_orig:
97         kfree(orig_data);
98         return err ? err : ret;
99  }