aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2016-11-18 13:24:26 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-06 04:40:13 -0500
commit956e2a0e6779824877822864ad486f08184f1a3e (patch)
treee0ad26f3398e40fcd6fad125ea99722b65065a8b /fs
parent01772f4683a9f92a06b3d2467c0084df2a512f35 (diff)
ext4: fix in-superblock mount options processing
commit 5aee0f8a3f42c94c5012f1673420aee96315925a upstream. Fix a large number of problems with how we handle mount options in the superblock. For one, if the string in the superblock is long enough that it is not null terminated, we could run off the end of the string and try to interpret superblocks fields as characters. It's unlikely this will cause a security problem, but it could result in an invalid parse. Also, parse_options is destructive to the string, so in some cases if there is a comma-separated string, it would be modified in the superblock. (Fortunately it only happens on file systems with a 1k block size.) Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/super.c38
1 files changed, 23 insertions, 15 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2113aad08c89..74596847c927 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3301,7 +3301,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3301 char *orig_data = kstrdup(data, GFP_KERNEL); 3301 char *orig_data = kstrdup(data, GFP_KERNEL);
3302 struct buffer_head *bh; 3302 struct buffer_head *bh;
3303 struct ext4_super_block *es = NULL; 3303 struct ext4_super_block *es = NULL;
3304 struct ext4_sb_info *sbi; 3304 struct ext4_sb_info *sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
3305 ext4_fsblk_t block; 3305 ext4_fsblk_t block;
3306 ext4_fsblk_t sb_block = get_sb_block(&data); 3306 ext4_fsblk_t sb_block = get_sb_block(&data);
3307 ext4_fsblk_t logical_sb_block; 3307 ext4_fsblk_t logical_sb_block;
@@ -3320,16 +3320,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3320 unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; 3320 unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
3321 ext4_group_t first_not_zeroed; 3321 ext4_group_t first_not_zeroed;
3322 3322
3323 sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 3323 if ((data && !orig_data) || !sbi)
3324 if (!sbi) 3324 goto out_free_base;
3325 goto out_free_orig;
3326 3325
3327 sbi->s_blockgroup_lock = 3326 sbi->s_blockgroup_lock =
3328 kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); 3327 kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL);
3329 if (!sbi->s_blockgroup_lock) { 3328 if (!sbi->s_blockgroup_lock)
3330 kfree(sbi); 3329 goto out_free_base;
3331 goto out_free_orig; 3330
3332 }
3333 sb->s_fs_info = sbi; 3331 sb->s_fs_info = sbi;
3334 sbi->s_sb = sb; 3332 sbi->s_sb = sb;
3335 sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; 3333 sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
@@ -3475,11 +3473,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3475 */ 3473 */
3476 sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; 3474 sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
3477 3475
3478 if (!parse_options((char *) sbi->s_es->s_mount_opts, sb, 3476 if (sbi->s_es->s_mount_opts[0]) {
3479 &journal_devnum, &journal_ioprio, 0)) { 3477 char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts,
3480 ext4_msg(sb, KERN_WARNING, 3478 sizeof(sbi->s_es->s_mount_opts),
3481 "failed to parse options in superblock: %s", 3479 GFP_KERNEL);
3482 sbi->s_es->s_mount_opts); 3480 if (!s_mount_opts)
3481 goto failed_mount;
3482 if (!parse_options(s_mount_opts, sb, &journal_devnum,
3483 &journal_ioprio, 0)) {
3484 ext4_msg(sb, KERN_WARNING,
3485 "failed to parse options in superblock: %s",
3486 s_mount_opts);
3487 }
3488 kfree(s_mount_opts);
3483 } 3489 }
3484 sbi->s_def_mount_opt = sbi->s_mount_opt; 3490 sbi->s_def_mount_opt = sbi->s_mount_opt;
3485 if (!parse_options((char *) data, sb, &journal_devnum, 3491 if (!parse_options((char *) data, sb, &journal_devnum,
@@ -4157,7 +4163,9 @@ no_journal:
4157 4163
4158 if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount")) 4164 if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount"))
4159 ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. " 4165 ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
4160 "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, 4166 "Opts: %.*s%s%s", descr,
4167 (int) sizeof(sbi->s_es->s_mount_opts),
4168 sbi->s_es->s_mount_opts,
4161 *sbi->s_es->s_mount_opts ? "; " : "", orig_data); 4169 *sbi->s_es->s_mount_opts ? "; " : "", orig_data);
4162 4170
4163 if (es->s_error_count) 4171 if (es->s_error_count)
@@ -4236,8 +4244,8 @@ failed_mount:
4236out_fail: 4244out_fail:
4237 sb->s_fs_info = NULL; 4245 sb->s_fs_info = NULL;
4238 kfree(sbi->s_blockgroup_lock); 4246 kfree(sbi->s_blockgroup_lock);
4247out_free_base:
4239 kfree(sbi); 4248 kfree(sbi);
4240out_free_orig:
4241 kfree(orig_data); 4249 kfree(orig_data);
4242 return err ? err : ret; 4250 return err ? err : ret;
4243} 4251}