diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 13:55:28 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-18 13:55:28 -0500 |
| commit | a2faf2fc534f57ba26bc4d613795236ed4f5fb1c (patch) | |
| tree | d75c4daadb469c8f08c498532fbf1fff68879e69 /kernel | |
| parent | 4351654e3ddf86a04966163dce4def586303e5cc (diff) | |
| parent | 5155040ed349950e16c093ba8e65ad534994df2a (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull (again) user namespace infrastructure changes from Eric Biederman:
"Those bugs, those darn embarrasing bugs just want don't want to get
fixed.
Linus I just updated my mirror of your kernel.org tree and it appears
you successfully pulled everything except the last 4 commits that fix
those embarrasing bugs.
When you get a chance can you please repull my branch"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
userns: Fix typo in description of the limitation of userns_install
userns: Add a more complete capability subset test to commit_creds
userns: Require CAP_SYS_ADMIN for most uses of setns.
Fix cap_capable to only allow owners in the parent user namespace to have caps.
Diffstat (limited to 'kernel')
| -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 |
4 files changed, 31 insertions, 4 deletions
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); |
