Skip to content

Commit

Permalink
ext3: Fix memory leak when quota options are specified multiple times
Browse files Browse the repository at this point in the history
When usrjquota or grpjquota mount options are specified several times,
we leak memory storing the names. Free the memory correctly.

Reported-by: Chen Gang <[email protected]>
Signed-off-by: Jan Kara <[email protected]>
  • Loading branch information
jankara committed Jan 21, 2013
1 parent 306a749 commit f56426a
Showing 1 changed file with 30 additions and 21 deletions.
51 changes: 30 additions & 21 deletions fs/ext3/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -916,21 +916,24 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
"Not enough memory for storing quotafile name");
return 0;
}
if (sbi->s_qf_names[qtype] &&
strcmp(sbi->s_qf_names[qtype], qname)) {
ext3_msg(sb, KERN_ERR,
"%s quota file already specified", QTYPE2NAME(qtype));
if (sbi->s_qf_names[qtype]) {
int same = !strcmp(sbi->s_qf_names[qtype], qname);

kfree(qname);
return 0;
if (!same) {
ext3_msg(sb, KERN_ERR,
"%s quota file already specified",
QTYPE2NAME(qtype));
}
return same;
}
sbi->s_qf_names[qtype] = qname;
if (strchr(sbi->s_qf_names[qtype], '/')) {
if (strchr(qname, '/')) {
ext3_msg(sb, KERN_ERR,
"quotafile must be on filesystem root");
kfree(sbi->s_qf_names[qtype]);
sbi->s_qf_names[qtype] = NULL;
kfree(qname);
return 0;
}
sbi->s_qf_names[qtype] = qname;
set_opt(sbi->s_mount_opt, QUOTA);
return 1;
}
Expand All @@ -945,11 +948,10 @@ static int clear_qf_name(struct super_block *sb, int qtype) {
" when quota turned on");
return 0;
}
/*
* The space will be released later when all options are confirmed
* to be correct
*/
sbi->s_qf_names[qtype] = NULL;
if (sbi->s_qf_names[qtype]) {
kfree(sbi->s_qf_names[qtype]);
sbi->s_qf_names[qtype] = NULL;
}
return 1;
}
#endif
Expand Down Expand Up @@ -2605,7 +2607,18 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
#ifdef CONFIG_QUOTA
old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++)
old_opts.s_qf_names[i] = sbi->s_qf_names[i];
if (sbi->s_qf_names[i]) {
old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
GFP_KERNEL);
if (!old_opts.s_qf_names[i]) {
int j;

for (j = 0; j < i; j++)
kfree(old_opts.s_qf_names[j]);
return -ENOMEM;
}
} else
old_opts.s_qf_names[i] = NULL;
#endif

/*
Expand Down Expand Up @@ -2698,9 +2711,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
#ifdef CONFIG_QUOTA
/* Release old quota file names */
for (i = 0; i < MAXQUOTAS; i++)
if (old_opts.s_qf_names[i] &&
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
kfree(old_opts.s_qf_names[i]);
kfree(old_opts.s_qf_names[i]);
#endif
if (enable_quota)
dquot_resume(sb, -1);
Expand All @@ -2714,9 +2725,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
#ifdef CONFIG_QUOTA
sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++) {
if (sbi->s_qf_names[i] &&
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
kfree(sbi->s_qf_names[i]);
kfree(sbi->s_qf_names[i]);
sbi->s_qf_names[i] = old_opts.s_qf_names[i];
}
#endif
Expand Down

0 comments on commit f56426a

Please sign in to comment.