mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-01 12:04:08 +00:00
[PATCH] fix races and leaks in vfs_quota_on() users
* new helper: vfs_quota_on_path(); equivalent of vfs_quota_on() sans the pathname resolution. * callers of vfs_quota_on() that do their own pathname resolution and checks based on it are switched to vfs_quota_on_path(); that way we avoid the races. * reiserfs leaked dentry/vfsmount references on several failure exits. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
1b7e190b47
commit
77e69dac3c
5 changed files with 35 additions and 22 deletions
33
fs/dquot.c
33
fs/dquot.c
|
@ -1793,6 +1793,21 @@ static int vfs_quota_on_remount(struct super_block *sb, int type)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
|
||||||
|
struct path *path)
|
||||||
|
{
|
||||||
|
int error = security_quota_on(path->dentry);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
/* Quota file not on the same filesystem? */
|
||||||
|
if (path->mnt->mnt_sb != sb)
|
||||||
|
error = -EXDEV;
|
||||||
|
else
|
||||||
|
error = vfs_quota_on_inode(path->dentry->d_inode, type,
|
||||||
|
format_id);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/* Actual function called from quotactl() */
|
/* Actual function called from quotactl() */
|
||||||
int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path,
|
int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path,
|
||||||
int remount)
|
int remount)
|
||||||
|
@ -1804,19 +1819,10 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path,
|
||||||
return vfs_quota_on_remount(sb, type);
|
return vfs_quota_on_remount(sb, type);
|
||||||
|
|
||||||
error = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
error = path_lookup(path, LOOKUP_FOLLOW, &nd);
|
||||||
if (error < 0)
|
if (!error) {
|
||||||
return error;
|
error = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||||
error = security_quota_on(nd.path.dentry);
|
path_put(&nd.path);
|
||||||
if (error)
|
}
|
||||||
goto out_path;
|
|
||||||
/* Quota file not on the same filesystem? */
|
|
||||||
if (nd.path.mnt->mnt_sb != sb)
|
|
||||||
error = -EXDEV;
|
|
||||||
else
|
|
||||||
error = vfs_quota_on_inode(nd.path.dentry->d_inode, type,
|
|
||||||
format_id);
|
|
||||||
out_path:
|
|
||||||
path_put(&nd.path);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2185,6 +2191,7 @@ EXPORT_SYMBOL(unregister_quota_format);
|
||||||
EXPORT_SYMBOL(dqstats);
|
EXPORT_SYMBOL(dqstats);
|
||||||
EXPORT_SYMBOL(dq_data_lock);
|
EXPORT_SYMBOL(dq_data_lock);
|
||||||
EXPORT_SYMBOL(vfs_quota_on);
|
EXPORT_SYMBOL(vfs_quota_on);
|
||||||
|
EXPORT_SYMBOL(vfs_quota_on_path);
|
||||||
EXPORT_SYMBOL(vfs_quota_on_mount);
|
EXPORT_SYMBOL(vfs_quota_on_mount);
|
||||||
EXPORT_SYMBOL(vfs_quota_off);
|
EXPORT_SYMBOL(vfs_quota_off);
|
||||||
EXPORT_SYMBOL(vfs_quota_sync);
|
EXPORT_SYMBOL(vfs_quota_sync);
|
||||||
|
|
|
@ -2810,8 +2810,9 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
journal_unlock_updates(EXT3_SB(sb)->s_journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||||
path_put(&nd.path);
|
path_put(&nd.path);
|
||||||
return vfs_quota_on(sb, type, format_id, path, remount);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
||||||
|
|
|
@ -3352,8 +3352,9 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
|
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||||
path_put(&nd.path);
|
path_put(&nd.path);
|
||||||
return vfs_quota_on(sb, type, format_id, path, remount);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
||||||
|
|
|
@ -2076,8 +2076,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
return err;
|
return err;
|
||||||
/* Quotafile not on the same filesystem? */
|
/* Quotafile not on the same filesystem? */
|
||||||
if (nd.path.mnt->mnt_sb != sb) {
|
if (nd.path.mnt->mnt_sb != sb) {
|
||||||
path_put(&nd.path);
|
err = -EXDEV;
|
||||||
return -EXDEV;
|
goto out;
|
||||||
}
|
}
|
||||||
inode = nd.path.dentry->d_inode;
|
inode = nd.path.dentry->d_inode;
|
||||||
/* We must not pack tails for quota files on reiserfs for quota IO to work */
|
/* We must not pack tails for quota files on reiserfs for quota IO to work */
|
||||||
|
@ -2087,8 +2087,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
reiserfs_warning(sb,
|
reiserfs_warning(sb,
|
||||||
"reiserfs: Unpacking tail of quota file failed"
|
"reiserfs: Unpacking tail of quota file failed"
|
||||||
" (%d). Cannot turn on quotas.", err);
|
" (%d). Cannot turn on quotas.", err);
|
||||||
path_put(&nd.path);
|
err = -EINVAL;
|
||||||
return -EINVAL;
|
goto out;
|
||||||
}
|
}
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
}
|
}
|
||||||
|
@ -2109,13 +2109,15 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
/* Just start temporary transaction and finish it */
|
/* Just start temporary transaction and finish it */
|
||||||
err = journal_begin(&th, sb, 1);
|
err = journal_begin(&th, sb, 1);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto out;
|
||||||
err = journal_end_sync(&th, sb, 1);
|
err = journal_end_sync(&th, sb, 1);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
err = vfs_quota_on_path(sb, type, format_id, &nd.path);
|
||||||
|
out:
|
||||||
path_put(&nd.path);
|
path_put(&nd.path);
|
||||||
return vfs_quota_on(sb, type, format_id, path, 0);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
||||||
|
|
|
@ -43,6 +43,8 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
|
||||||
|
|
||||||
int vfs_quota_on(struct super_block *sb, int type, int format_id,
|
int vfs_quota_on(struct super_block *sb, int type, int format_id,
|
||||||
char *path, int remount);
|
char *path, int remount);
|
||||||
|
int vfs_quota_on_path(struct super_block *sb, int type, int format_id,
|
||||||
|
struct path *path);
|
||||||
int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
|
int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
|
||||||
int format_id, int type);
|
int format_id, int type);
|
||||||
int vfs_quota_off(struct super_block *sb, int type, int remount);
|
int vfs_quota_off(struct super_block *sb, int type, int remount);
|
||||||
|
|
Loading…
Add table
Reference in a new issue