|
@@ -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 */
|