Commit 9b75450d authored by Konstantin Komarov's avatar Konstantin Komarov

fs/ntfs3: Fix memory leak if fill_super failed

In ntfs_init_fs_context we allocate memory in fc->s_fs_info.
In case of failed mount we must free it in ntfs_fill_super.
We can't do it in ntfs_fs_free, because ntfs_fs_free called
with fc->s_fs_info == NULL.
fc->s_fs_info became NULL in sget_fc.
Signed-off-by: default avatarKonstantin Komarov <almaz.alexandrovich@paragon-software.com>
parent ce46ae0c
...@@ -908,7 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -908,7 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (IS_ERR(sbi->options->nls)) { if (IS_ERR(sbi->options->nls)) {
sbi->options->nls = NULL; sbi->options->nls = NULL;
errorf(fc, "Cannot load nls %s", sbi->options->nls_name); errorf(fc, "Cannot load nls %s", sbi->options->nls_name);
return -EINVAL; err = -EINVAL;
goto out;
} }
rq = bdev_get_queue(bdev); rq = bdev_get_queue(bdev);
...@@ -922,7 +923,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -922,7 +923,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
err = ntfs_init_from_boot(sb, rq ? queue_logical_block_size(rq) : 512, err = ntfs_init_from_boot(sb, rq ? queue_logical_block_size(rq) : 512,
bdev->bd_inode->i_size); bdev->bd_inode->i_size);
if (err) if (err)
return err; goto out;
/* /*
* Load $Volume. This should be done before $LogFile * Load $Volume. This should be done before $LogFile
...@@ -933,7 +934,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -933,7 +934,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_VOLUME); inode = ntfs_iget5(sb, &ref, &NAME_VOLUME);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $Volume."); ntfs_err(sb, "Failed to load $Volume.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
ni = ntfs_i(inode); ni = ntfs_i(inode);
...@@ -954,19 +956,19 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -954,19 +956,19 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
} else { } else {
/* Should we break mounting here? */ /* Should we break mounting here? */
//err = -EINVAL; //err = -EINVAL;
//goto out; //goto put_inode_out;
} }
attr = ni_find_attr(ni, attr, NULL, ATTR_VOL_INFO, NULL, 0, NULL, NULL); attr = ni_find_attr(ni, attr, NULL, ATTR_VOL_INFO, NULL, 0, NULL, NULL);
if (!attr || is_attr_ext(attr)) { if (!attr || is_attr_ext(attr)) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO); info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO);
if (!info) { if (!info) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
sbi->volume.major_ver = info->major_ver; sbi->volume.major_ver = info->major_ver;
...@@ -980,7 +982,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -980,7 +982,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_MIRROR); inode = ntfs_iget5(sb, &ref, &NAME_MIRROR);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $MFTMirr."); ntfs_err(sb, "Failed to load $MFTMirr.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
sbi->mft.recs_mirr = sbi->mft.recs_mirr =
...@@ -994,14 +997,15 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -994,14 +997,15 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE); inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load \x24LogFile."); ntfs_err(sb, "Failed to load \x24LogFile.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
ni = ntfs_i(inode); ni = ntfs_i(inode);
err = ntfs_loadlog_and_replay(ni, sbi); err = ntfs_loadlog_and_replay(ni, sbi);
if (err) if (err)
goto out; goto put_inode_out;
iput(inode); iput(inode);
...@@ -1009,14 +1013,16 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1009,14 +1013,16 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (!sb_rdonly(sb)) { if (!sb_rdonly(sb)) {
ntfs_warn(sb, ntfs_warn(sb,
"failed to replay log file. Can't mount rw!"); "failed to replay log file. Can't mount rw!");
return -EINVAL; err = -EINVAL;
goto out;
} }
} else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) { } else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) {
if (!sb_rdonly(sb) && !sbi->options->force) { if (!sb_rdonly(sb) && !sbi->options->force) {
ntfs_warn( ntfs_warn(
sb, sb,
"volume is dirty and \"force\" flag is not set!"); "volume is dirty and \"force\" flag is not set!");
return -EINVAL; err = -EINVAL;
goto out;
} }
} }
...@@ -1027,7 +1033,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1027,7 +1033,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_MFT); inode = ntfs_iget5(sb, &ref, &NAME_MFT);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $MFT."); ntfs_err(sb, "Failed to load $MFT.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
ni = ntfs_i(inode); ni = ntfs_i(inode);
...@@ -1038,11 +1045,11 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1038,11 +1045,11 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
err = wnd_init(&sbi->mft.bitmap, sb, tt); err = wnd_init(&sbi->mft.bitmap, sb, tt);
if (err) if (err)
goto out; goto put_inode_out;
err = ni_load_all_mi(ni); err = ni_load_all_mi(ni);
if (err) if (err)
goto out; goto put_inode_out;
sbi->mft.ni = ni; sbi->mft.ni = ni;
...@@ -1052,7 +1059,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1052,7 +1059,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS); inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $BadClus."); ntfs_err(sb, "Failed to load $BadClus.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
ni = ntfs_i(inode); ni = ntfs_i(inode);
...@@ -1075,13 +1083,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1075,13 +1083,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_BITMAP); inode = ntfs_iget5(sb, &ref, &NAME_BITMAP);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $Bitmap."); ntfs_err(sb, "Failed to load $Bitmap.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
#ifndef CONFIG_NTFS3_64BIT_CLUSTER #ifndef CONFIG_NTFS3_64BIT_CLUSTER
if (inode->i_size >> 32) { if (inode->i_size >> 32) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
#endif #endif
...@@ -1089,21 +1098,21 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1089,21 +1098,21 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
tt = sbi->used.bitmap.nbits; tt = sbi->used.bitmap.nbits;
if (inode->i_size < bitmap_size(tt)) { if (inode->i_size < bitmap_size(tt)) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
/* Not necessary. */ /* Not necessary. */
sbi->used.bitmap.set_tail = true; sbi->used.bitmap.set_tail = true;
err = wnd_init(&sbi->used.bitmap, sb, tt); err = wnd_init(&sbi->used.bitmap, sb, tt);
if (err) if (err)
goto out; goto put_inode_out;
iput(inode); iput(inode);
/* Compute the MFT zone. */ /* Compute the MFT zone. */
err = ntfs_refresh_zone(sbi); err = ntfs_refresh_zone(sbi);
if (err) if (err)
return err; goto out;
/* Load $AttrDef. */ /* Load $AttrDef. */
ref.low = cpu_to_le32(MFT_REC_ATTR); ref.low = cpu_to_le32(MFT_REC_ATTR);
...@@ -1111,18 +1120,19 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1111,18 +1120,19 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF); inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $AttrDef -> %d", err); ntfs_err(sb, "Failed to load $AttrDef -> %d", err);
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY)) { if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY)) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
bytes = inode->i_size; bytes = inode->i_size;
sbi->def_table = t = kmalloc(bytes, GFP_NOFS); sbi->def_table = t = kmalloc(bytes, GFP_NOFS);
if (!t) { if (!t) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto put_inode_out;
} }
for (done = idx = 0; done < bytes; done += PAGE_SIZE, idx++) { for (done = idx = 0; done < bytes; done += PAGE_SIZE, idx++) {
...@@ -1131,7 +1141,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1131,7 +1141,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (IS_ERR(page)) { if (IS_ERR(page)) {
err = PTR_ERR(page); err = PTR_ERR(page);
goto out; goto put_inode_out;
} }
memcpy(Add2Ptr(t, done), page_address(page), memcpy(Add2Ptr(t, done), page_address(page),
min(PAGE_SIZE, tail)); min(PAGE_SIZE, tail));
...@@ -1139,7 +1149,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1139,7 +1149,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (!idx && ATTR_STD != t->type) { if (!idx && ATTR_STD != t->type) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
} }
...@@ -1173,12 +1183,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1173,12 +1183,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_UPCASE); inode = ntfs_iget5(sb, &ref, &NAME_UPCASE);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load $UpCase."); ntfs_err(sb, "Failed to load $UpCase.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
if (inode->i_size != 0x10000 * sizeof(short)) { if (inode->i_size != 0x10000 * sizeof(short)) {
err = -EINVAL; err = -EINVAL;
goto out; goto put_inode_out;
} }
for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) { for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) {
...@@ -1188,7 +1199,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1188,7 +1199,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (IS_ERR(page)) { if (IS_ERR(page)) {
err = PTR_ERR(page); err = PTR_ERR(page);
goto out; goto put_inode_out;
} }
src = page_address(page); src = page_address(page);
...@@ -1214,7 +1225,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1214,7 +1225,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
/* Load $Secure. */ /* Load $Secure. */
err = ntfs_security_init(sbi); err = ntfs_security_init(sbi);
if (err) if (err)
return err; goto out;
/* Load $Extend. */ /* Load $Extend. */
err = ntfs_extend_init(sbi); err = ntfs_extend_init(sbi);
...@@ -1239,19 +1250,30 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1239,19 +1250,30 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
inode = ntfs_iget5(sb, &ref, &NAME_ROOT); inode = ntfs_iget5(sb, &ref, &NAME_ROOT);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
ntfs_err(sb, "Failed to load root."); ntfs_err(sb, "Failed to load root.");
return PTR_ERR(inode); err = PTR_ERR(inode);
goto out;
} }
sb->s_root = d_make_root(inode); sb->s_root = d_make_root(inode);
if (!sb->s_root) if (!sb->s_root) {
return -ENOMEM; err = -ENOMEM;
goto put_inode_out;
}
fc->fs_private = NULL; fc->fs_private = NULL;
fc->s_fs_info = NULL;
return 0; return 0;
out:
put_inode_out:
iput(inode); iput(inode);
out:
/*
* Free resources here.
* ntfs_fs_free will be called with fc->s_fs_info = NULL
*/
put_ntfs(sbi);
sb->s_fs_info = NULL;
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment