diff options
| -rw-r--r-- | fs/inode.c | 6 | ||||
| -rw-r--r-- | fs/namei.c | 18 | ||||
| -rw-r--r-- | include/linux/capability.h | 2 | ||||
| -rw-r--r-- | include/linux/fs.h | 6 | ||||
| -rw-r--r-- | kernel/capability.c | 19 | 
5 files changed, 28 insertions, 23 deletions
diff --git a/fs/inode.c b/fs/inode.c index 9f4f5fecc09..f0c4ace408e 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1732,11 +1732,9 @@ EXPORT_SYMBOL(inode_init_owner);   */  bool inode_owner_or_capable(const struct inode *inode)  { -	struct user_namespace *ns = inode_userns(inode); - -	if (current_user_ns() == ns && current_fsuid() == inode->i_uid) +	if (current_fsuid() == inode->i_uid)  		return true; -	if (ns_capable(ns, CAP_FOWNER)) +	if (inode_capable(inode, CAP_FOWNER))  		return true;  	return false;  } diff --git a/fs/namei.c b/fs/namei.c index 701954d68ac..941c4362e29 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -228,9 +228,6 @@ static int acl_permission_check(struct inode *inode, int mask)  {  	unsigned int mode = inode->i_mode; -	if (current_user_ns() != inode_userns(inode)) -		goto other_perms; -  	if (likely(current_fsuid() == inode->i_uid))  		mode >>= 6;  	else { @@ -244,7 +241,6 @@ static int acl_permission_check(struct inode *inode, int mask)  			mode >>= 3;  	} -other_perms:  	/*  	 * If the DACs are ok we don't need any capability check.  	 */ @@ -280,10 +276,10 @@ int generic_permission(struct inode *inode, int mask)  	if (S_ISDIR(inode->i_mode)) {  		/* DACs are overridable for directories */ -		if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) +		if (inode_capable(inode, CAP_DAC_OVERRIDE))  			return 0;  		if (!(mask & MAY_WRITE)) -			if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) +			if (inode_capable(inode, CAP_DAC_READ_SEARCH))  				return 0;  		return -EACCES;  	} @@ -293,7 +289,7 @@ int generic_permission(struct inode *inode, int mask)  	 * at least one exec bit set.  	 */  	if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) -		if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) +		if (inode_capable(inode, CAP_DAC_OVERRIDE))  			return 0;  	/* @@ -301,7 +297,7 @@ int generic_permission(struct inode *inode, int mask)  	 */  	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;  	if (mask == MAY_READ) -		if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) +		if (inode_capable(inode, CAP_DAC_READ_SEARCH))  			return 0;  	return -EACCES; @@ -1964,15 +1960,11 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)  	if (!(dir->i_mode & S_ISVTX))  		return 0; -	if (current_user_ns() != inode_userns(inode)) -		goto other_userns;  	if (inode->i_uid == fsuid)  		return 0;  	if (dir->i_uid == fsuid)  		return 0; - -other_userns: -	return !ns_capable(inode_userns(inode), CAP_FOWNER); +	return !inode_capable(inode, CAP_FOWNER);  }  /* diff --git a/include/linux/capability.h b/include/linux/capability.h index 12d52dedb22..a76eca90747 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -374,6 +374,7 @@ struct cpu_vfs_cap_data {  #ifdef __KERNEL__ +struct inode;  struct dentry;  struct user_namespace; @@ -548,6 +549,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,  extern bool capable(int cap);  extern bool ns_capable(struct user_namespace *ns, int cap);  extern bool nsown_capable(int cap); +extern bool inode_capable(const struct inode *inode, int cap);  /* audit system wants to get cap info from files as well */  extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); diff --git a/include/linux/fs.h b/include/linux/fs.h index 135693e79f2..a6c5efbee0d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1522,12 +1522,6 @@ enum {  #define vfs_check_frozen(sb, level) \  	wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) -/* - * until VFS tracks user namespaces for inodes, just make all files - * belong to init_user_ns - */ -extern struct user_namespace init_user_ns; -#define inode_userns(inode) (&init_user_ns)  extern bool inode_owner_or_capable(const struct inode *inode);  /* not quite ready to be deprecated, but... */ diff --git a/kernel/capability.c b/kernel/capability.c index 3f1adb6c647..cc5f0718215 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -419,3 +419,22 @@ bool nsown_capable(int cap)  {  	return ns_capable(current_user_ns(), cap);  } + +/** + * inode_capable - Check superior capability over inode + * @inode: The inode in question + * @cap: The capability in question + * + * Return true if the current task has the given superior capability + * targeted at it's own user namespace and that the given inode is owned + * by the current user namespace or a child namespace. + * + * Currently inodes can only be owned by the initial user namespace. + * + */ +bool inode_capable(const struct inode *inode, int cap) +{ +	struct user_namespace *ns = current_user_ns(); + +	return ns_capable(ns, cap) && (ns == &init_user_ns); +}  |