Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35033ab9 authored by OGAWA Hirofumi's avatar OGAWA Hirofumi Committed by Linus Torvalds
Browse files

fat: fix memory allocation failure handling of match_strdup()

In parse_options(), if match_strdup() failed, parse_options() leaves
opts->iocharset in unexpected state (i.e.  still pointing the freed
string).  And this can be the cause of double free.

To fix, this initialize opts->iocharset always when freeing.

Link: http://lkml.kernel.org/r/8736wp9dzc.fsf@mail.parknet.co.jp


Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Reported-by: default avatar <syzbot+90b8e10515ae88228a92@syzkaller.appspotmail.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5a696494
Loading
Loading
Loading
Loading
+13 −7
Original line number Diff line number Diff line
@@ -707,13 +707,21 @@ static void fat_set_state(struct super_block *sb,
	brelse(bh);
}

static void fat_reset_iocharset(struct fat_mount_options *opts)
{
	if (opts->iocharset != fat_default_iocharset) {
		/* Note: opts->iocharset can be NULL here */
		kfree(opts->iocharset);
		opts->iocharset = fat_default_iocharset;
	}
}

static void delayed_free(struct rcu_head *p)
{
	struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu);
	unload_nls(sbi->nls_disk);
	unload_nls(sbi->nls_io);
	if (sbi->options.iocharset != fat_default_iocharset)
		kfree(sbi->options.iocharset);
	fat_reset_iocharset(&sbi->options);
	kfree(sbi);
}

@@ -1132,7 +1140,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
	opts->fs_fmask = opts->fs_dmask = current_umask();
	opts->allow_utime = -1;
	opts->codepage = fat_default_codepage;
	opts->iocharset = fat_default_iocharset;
	fat_reset_iocharset(opts);
	if (is_vfat) {
		opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95;
		opts->rodir = 0;
@@ -1289,8 +1297,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,

		/* vfat specific */
		case Opt_charset:
			if (opts->iocharset != fat_default_iocharset)
				kfree(opts->iocharset);
			fat_reset_iocharset(opts);
			iocharset = match_strdup(&args[0]);
			if (!iocharset)
				return -ENOMEM;
@@ -1881,8 +1888,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
		iput(fat_inode);
	unload_nls(sbi->nls_io);
	unload_nls(sbi->nls_disk);
	if (sbi->options.iocharset != fat_default_iocharset)
		kfree(sbi->options.iocharset);
	fat_reset_iocharset(&sbi->options);
	sb->s_fs_info = NULL;
	kfree(sbi);
	return error;