diff options
Diffstat (limited to 'security/commoncap.c')
| -rw-r--r-- | security/commoncap.c | 25 | 
1 files changed, 17 insertions, 8 deletions
diff --git a/security/commoncap.c b/security/commoncap.c index 6dbae4650ab..7ee08c756d6 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -76,24 +76,33 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)  int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,  		int cap, int audit)  { -	for (;;) { -		/* The owner of the user namespace has all caps. */ -		if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid)) -			return 0; +	struct user_namespace *ns = targ_ns; +	/* See if cred has the capability in the target user namespace +	 * by examining the target user namespace and all of the target +	 * user namespace's parents. +	 */ +	for (;;) {  		/* Do we have the necessary capabilities? */ -		if (targ_ns == cred->user_ns) +		if (ns == cred->user_ns)  			return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;  		/* Have we tried all of the parent namespaces? */ -		if (targ_ns == &init_user_ns) +		if (ns == &init_user_ns)  			return -EPERM; +		/*  +		 * The owner of the user namespace in the parent of the +		 * user namespace has all caps. +		 */ +		if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid)) +			return 0; +  		/* -		 *If you have a capability in a parent user ns, then you have +		 * If you have a capability in a parent user ns, then you have  		 * it over all children user namespaces as well.  		 */ -		targ_ns = targ_ns->parent; +		ns = ns->parent;  	}  	/* We never get here */  |