Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more vfs updates from Al Viro: "Assorted VFS fixes and related cleanups (IMO the most interesting in that part are f_path-related things and Eric's descriptor-related stuff). UFS regression fixes (it got broken last cycle). 9P fixes. fs-cache series, DAX patches, Jan's file_remove_suid() work" [ I'd say this is much more than "fixes and related cleanups". The file_table locking rule change by Eric Dumazet is a rather big and fundamental update even if the patch isn't huge. - Linus ] * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (49 commits) 9p: cope with bogus responses from server in p9_client_{read,write} p9_client_write(): avoid double p9_free_req() 9p: forgetting to cancel request on interrupted zero-copy RPC dax: bdev_direct_access() may sleep block: Add support for DAX reads/writes to block devices dax: Use copy_from_iter_nocache dax: Add block size note to documentation fs/file.c: __fget() and dup2() atomicity rules fs/file.c: don't acquire files->file_lock in fd_install() fs:super:get_anon_bdev: fix race condition could cause dev exceed its upper limitation vfs: avoid creation of inode number 0 in get_next_ino namei: make set_root_rcu() return void make simple_positive() public ufs: use dir_pages instead of ufs_dir_pages() pagemap.h: move dir_pages() over there remove the pointless include of lglock.h fs: cleanup slight list_entry abuse xfs: Correctly lock inode when removing suid and file capabilities fs: Call security_ops->inode_killpriv on truncate fs: Provide function telling whether file_remove_privs() will do anything ...
This commit is contained in:
66
fs/inode.c
66
fs/inode.c
@@ -841,7 +841,11 @@ unsigned int get_next_ino(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
*p = ++res;
|
||||
res++;
|
||||
/* get_next_ino should not provide a 0 inode number */
|
||||
if (unlikely(!res))
|
||||
res++;
|
||||
*p = res;
|
||||
put_cpu_var(last_ino);
|
||||
return res;
|
||||
}
|
||||
@@ -1674,7 +1678,31 @@ int should_remove_suid(struct dentry *dentry)
|
||||
}
|
||||
EXPORT_SYMBOL(should_remove_suid);
|
||||
|
||||
static int __remove_suid(struct dentry *dentry, int kill)
|
||||
/*
|
||||
* Return mask of changes for notify_change() that need to be done as a
|
||||
* response to write or truncate. Return 0 if nothing has to be changed.
|
||||
* Negative value on error (change should be denied).
|
||||
*/
|
||||
int dentry_needs_remove_privs(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int mask = 0;
|
||||
int ret;
|
||||
|
||||
if (IS_NOSEC(inode))
|
||||
return 0;
|
||||
|
||||
mask = should_remove_suid(dentry);
|
||||
ret = security_inode_need_killpriv(dentry);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret)
|
||||
mask |= ATTR_KILL_PRIV;
|
||||
return mask;
|
||||
}
|
||||
EXPORT_SYMBOL(dentry_needs_remove_privs);
|
||||
|
||||
static int __remove_privs(struct dentry *dentry, int kill)
|
||||
{
|
||||
struct iattr newattrs;
|
||||
|
||||
@@ -1686,33 +1714,32 @@ static int __remove_suid(struct dentry *dentry, int kill)
|
||||
return notify_change(dentry, &newattrs, NULL);
|
||||
}
|
||||
|
||||
int file_remove_suid(struct file *file)
|
||||
/*
|
||||
* Remove special file priviledges (suid, capabilities) when file is written
|
||||
* to or truncated.
|
||||
*/
|
||||
int file_remove_privs(struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int killsuid;
|
||||
int killpriv;
|
||||
int kill;
|
||||
int error = 0;
|
||||
|
||||
/* Fast path for nothing security related */
|
||||
if (IS_NOSEC(inode))
|
||||
return 0;
|
||||
|
||||
killsuid = should_remove_suid(dentry);
|
||||
killpriv = security_inode_need_killpriv(dentry);
|
||||
|
||||
if (killpriv < 0)
|
||||
return killpriv;
|
||||
if (killpriv)
|
||||
error = security_inode_killpriv(dentry);
|
||||
if (!error && killsuid)
|
||||
error = __remove_suid(dentry, killsuid);
|
||||
if (!error && (inode->i_sb->s_flags & MS_NOSEC))
|
||||
inode->i_flags |= S_NOSEC;
|
||||
kill = file_needs_remove_privs(file);
|
||||
if (kill < 0)
|
||||
return kill;
|
||||
if (kill)
|
||||
error = __remove_privs(dentry, kill);
|
||||
if (!error)
|
||||
inode_has_no_xattr(inode);
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(file_remove_suid);
|
||||
EXPORT_SYMBOL(file_remove_privs);
|
||||
|
||||
/**
|
||||
* file_update_time - update mtime and ctime time
|
||||
@@ -1967,9 +1994,8 @@ EXPORT_SYMBOL(inode_dio_wait);
|
||||
* inode is being instantiated). The reason for the cmpxchg() loop
|
||||
* --- which wouldn't be necessary if all code paths which modify
|
||||
* i_flags actually followed this rule, is that there is at least one
|
||||
* code path which doesn't today --- for example,
|
||||
* __generic_file_aio_write() calls file_remove_suid() without holding
|
||||
* i_mutex --- so we use cmpxchg() out of an abundance of caution.
|
||||
* code path which doesn't today so we use cmpxchg() out of an abundance
|
||||
* of caution.
|
||||
*
|
||||
* In the long run, i_mutex is overkill, and we should probably look
|
||||
* at using the i_lock spinlock to protect i_flags, and then make sure
|
||||
|
Reference in New Issue
Block a user