diff options
-rw-r--r-- | fs/namespace.c | 3 | ||||
-rw-r--r-- | ipc/namespace.c | 3 | ||||
-rw-r--r-- | kernel/cred.c | 27 | ||||
-rw-r--r-- | kernel/pid_namespace.c | 3 | ||||
-rw-r--r-- | kernel/user_namespace.c | 2 | ||||
-rw-r--r-- | kernel/utsname.c | 3 | ||||
-rw-r--r-- | net/core/net_namespace.c | 3 | ||||
-rw-r--r-- | security/commoncap.c | 25 |
8 files changed, 54 insertions, 15 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index c1bbe86f4920..398a50ff2438 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) | |||
2781 | struct path root; | 2781 | struct path root; |
2782 | 2782 | ||
2783 | if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || | 2783 | if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || |
2784 | !nsown_capable(CAP_SYS_CHROOT)) | 2784 | !nsown_capable(CAP_SYS_CHROOT) || |
2785 | !nsown_capable(CAP_SYS_ADMIN)) | ||
2785 | return -EPERM; | 2786 | return -EPERM; |
2786 | 2787 | ||
2787 | if (fs->users != 1) | 2788 | if (fs->users != 1) |
diff --git a/ipc/namespace.c b/ipc/namespace.c index cf3386a51de2..7c1fa451b0b0 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c | |||
@@ -170,7 +170,8 @@ static void ipcns_put(void *ns) | |||
170 | static int ipcns_install(struct nsproxy *nsproxy, void *new) | 170 | static int ipcns_install(struct nsproxy *nsproxy, void *new) |
171 | { | 171 | { |
172 | struct ipc_namespace *ns = new; | 172 | struct ipc_namespace *ns = new; |
173 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) | 173 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || |
174 | !nsown_capable(CAP_SYS_ADMIN)) | ||
174 | return -EPERM; | 175 | return -EPERM; |
175 | 176 | ||
176 | /* Ditch state from the old ipc namespace */ | 177 | /* Ditch state from the old ipc namespace */ |
diff --git a/kernel/cred.c b/kernel/cred.c index 8888afb846e9..e0573a43c7df 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -372,6 +372,31 @@ error_put: | |||
372 | return ret; | 372 | return ret; |
373 | } | 373 | } |
374 | 374 | ||
375 | static bool cred_cap_issubset(const struct cred *set, const struct cred *subset) | ||
376 | { | ||
377 | const struct user_namespace *set_ns = set->user_ns; | ||
378 | const struct user_namespace *subset_ns = subset->user_ns; | ||
379 | |||
380 | /* If the two credentials are in the same user namespace see if | ||
381 | * the capabilities of subset are a subset of set. | ||
382 | */ | ||
383 | if (set_ns == subset_ns) | ||
384 | return cap_issubset(subset->cap_permitted, set->cap_permitted); | ||
385 | |||
386 | /* The credentials are in a different user namespaces | ||
387 | * therefore one is a subset of the other only if a set is an | ||
388 | * ancestor of subset and set->euid is owner of subset or one | ||
389 | * of subsets ancestors. | ||
390 | */ | ||
391 | for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) { | ||
392 | if ((set_ns == subset_ns->parent) && | ||
393 | uid_eq(subset_ns->owner, set->euid)) | ||
394 | return true; | ||
395 | } | ||
396 | |||
397 | return false; | ||
398 | } | ||
399 | |||
375 | /** | 400 | /** |
376 | * commit_creds - Install new credentials upon the current task | 401 | * commit_creds - Install new credentials upon the current task |
377 | * @new: The credentials to be assigned | 402 | * @new: The credentials to be assigned |
@@ -410,7 +435,7 @@ int commit_creds(struct cred *new) | |||
410 | !gid_eq(old->egid, new->egid) || | 435 | !gid_eq(old->egid, new->egid) || |
411 | !uid_eq(old->fsuid, new->fsuid) || | 436 | !uid_eq(old->fsuid, new->fsuid) || |
412 | !gid_eq(old->fsgid, new->fsgid) || | 437 | !gid_eq(old->fsgid, new->fsgid) || |
413 | !cap_issubset(new->cap_permitted, old->cap_permitted)) { | 438 | !cred_cap_issubset(old, new)) { |
414 | if (task->mm) | 439 | if (task->mm) |
415 | set_dumpable(task->mm, suid_dumpable); | 440 | set_dumpable(task->mm, suid_dumpable); |
416 | task->pdeath_signal = 0; | 441 | task->pdeath_signal = 0; |
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 560da0dab230..fdbd0cdf271a 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c | |||
@@ -325,7 +325,8 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) | |||
325 | struct pid_namespace *active = task_active_pid_ns(current); | 325 | struct pid_namespace *active = task_active_pid_ns(current); |
326 | struct pid_namespace *ancestor, *new = ns; | 326 | struct pid_namespace *ancestor, *new = ns; |
327 | 327 | ||
328 | if (!ns_capable(new->user_ns, CAP_SYS_ADMIN)) | 328 | if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) || |
329 | !nsown_capable(CAP_SYS_ADMIN)) | ||
329 | return -EPERM; | 330 | return -EPERM; |
330 | 331 | ||
331 | /* | 332 | /* |
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index f5975ccf9348..2b042c42fbc4 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -799,7 +799,7 @@ static int userns_install(struct nsproxy *nsproxy, void *ns) | |||
799 | if (user_ns == current_user_ns()) | 799 | if (user_ns == current_user_ns()) |
800 | return -EINVAL; | 800 | return -EINVAL; |
801 | 801 | ||
802 | /* Threaded many not enter a different user namespace */ | 802 | /* Threaded processes may not enter a different user namespace */ |
803 | if (atomic_read(¤t->mm->mm_users) > 1) | 803 | if (atomic_read(¤t->mm->mm_users) > 1) |
804 | return -EINVAL; | 804 | return -EINVAL; |
805 | 805 | ||
diff --git a/kernel/utsname.c b/kernel/utsname.c index f6336d51d64c..08b197e8c485 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c | |||
@@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new) | |||
113 | { | 113 | { |
114 | struct uts_namespace *ns = new; | 114 | struct uts_namespace *ns = new; |
115 | 115 | ||
116 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) | 116 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || |
117 | !nsown_capable(CAP_SYS_ADMIN)) | ||
117 | return -EPERM; | 118 | return -EPERM; |
118 | 119 | ||
119 | get_uts_ns(ns); | 120 | get_uts_ns(ns); |
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 2e9a3132b8dd..8acce01b6dab 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) | |||
649 | { | 649 | { |
650 | struct net *net = ns; | 650 | struct net *net = ns; |
651 | 651 | ||
652 | if (!ns_capable(net->user_ns, CAP_SYS_ADMIN)) | 652 | if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || |
653 | !nsown_capable(CAP_SYS_ADMIN)) | ||
653 | return -EPERM; | 654 | return -EPERM; |
654 | 655 | ||
655 | put_net(nsproxy->net_ns); | 656 | put_net(nsproxy->net_ns); |
diff --git a/security/commoncap.c b/security/commoncap.c index 6dbae4650abe..7ee08c756d6b 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -76,24 +76,33 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb) | |||
76 | int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, | 76 | int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, |
77 | int cap, int audit) | 77 | int cap, int audit) |
78 | { | 78 | { |
79 | for (;;) { | 79 | struct user_namespace *ns = targ_ns; |
80 | /* The owner of the user namespace has all caps. */ | ||
81 | if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid)) | ||
82 | return 0; | ||
83 | 80 | ||
81 | /* See if cred has the capability in the target user namespace | ||
82 | * by examining the target user namespace and all of the target | ||
83 | * user namespace's parents. | ||
84 | */ | ||
85 | for (;;) { | ||
84 | /* Do we have the necessary capabilities? */ | 86 | /* Do we have the necessary capabilities? */ |
85 | if (targ_ns == cred->user_ns) | 87 | if (ns == cred->user_ns) |
86 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; | 88 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; |
87 | 89 | ||
88 | /* Have we tried all of the parent namespaces? */ | 90 | /* Have we tried all of the parent namespaces? */ |
89 | if (targ_ns == &init_user_ns) | 91 | if (ns == &init_user_ns) |
90 | return -EPERM; | 92 | return -EPERM; |
91 | 93 | ||
94 | /* | ||
95 | * The owner of the user namespace in the parent of the | ||
96 | * user namespace has all caps. | ||
97 | */ | ||
98 | if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid)) | ||
99 | return 0; | ||
100 | |||
92 | /* | 101 | /* |
93 | *If you have a capability in a parent user ns, then you have | 102 | * If you have a capability in a parent user ns, then you have |
94 | * it over all children user namespaces as well. | 103 | * it over all children user namespaces as well. |
95 | */ | 104 | */ |
96 | targ_ns = targ_ns->parent; | 105 | ns = ns->parent; |
97 | } | 106 | } |
98 | 107 | ||
99 | /* We never get here */ | 108 | /* We never get here */ |