aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-07 17:35:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-07 17:35:32 -0400
commitc7c4591db64dbd1e504bc4e2806d7ef290a3c81b (patch)
treea2fb124f9760eec668d20541383e762822d7cc7b /kernel
parent11c7b03d42a847db90862d0f9d8be6ce9b2f0553 (diff)
parentc7b96acf1456ef127fef461fcfedb54b81fecfbb (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace changes from Eric Biederman: "This is an assorted mishmash of small cleanups, enhancements and bug fixes. The major theme is user namespace mount restrictions. nsown_capable is killed as it encourages not thinking about details that need to be considered. A very hard to hit pid namespace exiting bug was finally tracked and fixed. A couple of cleanups to the basic namespace infrastructure. Finally there is an enhancement that makes per user namespace capabilities usable as capabilities, and an enhancement that allows the per userns root to nice other processes in the user namespace" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: userns: Kill nsown_capable it makes the wrong thing easy capabilities: allow nice if we are privileged pidns: Don't have unshare(CLONE_NEWPID) imply CLONE_THREAD userns: Allow PR_CAPBSET_DROP in a user namespace. namespaces: Simplify copy_namespaces so it is clear what is going on. pidns: Fix hang in zap_pid_ns_processes by sending a potentially extra wakeup sysfs: Restrict mounting sysfs userns: Better restrictions on when proc and sysfs can be mounted vfs: Don't copy mount bind mounts of /proc/<pid>/ns/mnt between namespaces kernel/nsproxy.c: Improving a snippet of code. proc: Restrict mounting the proc filesystem vfs: Lock in place mounts from more privileged users
Diffstat (limited to 'kernel')
-rw-r--r--kernel/capability.c12
-rw-r--r--kernel/fork.c5
-rw-r--r--kernel/groups.c2
-rw-r--r--kernel/nsproxy.c36
-rw-r--r--kernel/pid.c1
-rw-r--r--kernel/pid_namespace.c2
-rw-r--r--kernel/sys.c20
-rw-r--r--kernel/uid16.c2
-rw-r--r--kernel/user.c2
-rw-r--r--kernel/user_namespace.c2
-rw-r--r--kernel/utsname.c2
11 files changed, 27 insertions, 59 deletions
diff --git a/kernel/capability.c b/kernel/capability.c
index f6c2ce5701e1..6fc1c8af44df 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -433,18 +433,6 @@ bool capable(int cap)
433EXPORT_SYMBOL(capable); 433EXPORT_SYMBOL(capable);
434 434
435/** 435/**
436 * nsown_capable - Check superior capability to one's own user_ns
437 * @cap: The capability in question
438 *
439 * Return true if the current task has the given superior capability
440 * targeted at its own user namespace.
441 */
442bool nsown_capable(int cap)
443{
444 return ns_capable(current_user_ns(), cap);
445}
446
447/**
448 * inode_capable - Check superior capability over inode 436 * inode_capable - Check superior capability over inode
449 * @inode: The inode in question 437 * @inode: The inode in question
450 * @cap: The capability in question 438 * @cap: The capability in question
diff --git a/kernel/fork.c b/kernel/fork.c
index bf46287c91a4..c9eaf2013002 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1825,11 +1825,6 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags)
1825 if (unshare_flags & CLONE_NEWUSER) 1825 if (unshare_flags & CLONE_NEWUSER)
1826 unshare_flags |= CLONE_THREAD | CLONE_FS; 1826 unshare_flags |= CLONE_THREAD | CLONE_FS;
1827 /* 1827 /*
1828 * If unsharing a pid namespace must also unshare the thread.
1829 */
1830 if (unshare_flags & CLONE_NEWPID)
1831 unshare_flags |= CLONE_THREAD;
1832 /*
1833 * If unsharing a thread from a thread group, must also unshare vm. 1828 * If unsharing a thread from a thread group, must also unshare vm.
1834 */ 1829 */
1835 if (unshare_flags & CLONE_THREAD) 1830 if (unshare_flags & CLONE_THREAD)
diff --git a/kernel/groups.c b/kernel/groups.c
index 6b2588dd04ff..90cf1c38c8ea 100644
--- a/kernel/groups.c
+++ b/kernel/groups.c
@@ -233,7 +233,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
233 struct group_info *group_info; 233 struct group_info *group_info;
234 int retval; 234 int retval;
235 235
236 if (!nsown_capable(CAP_SETGID)) 236 if (!ns_capable(current_user_ns(), CAP_SETGID))
237 return -EPERM; 237 return -EPERM;
238 if ((unsigned)gidsetsize > NGROUPS_MAX) 238 if ((unsigned)gidsetsize > NGROUPS_MAX)
239 return -EINVAL; 239 return -EINVAL;
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 997cbb951a3b..8e7811086b82 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -126,22 +126,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
126 struct nsproxy *old_ns = tsk->nsproxy; 126 struct nsproxy *old_ns = tsk->nsproxy;
127 struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); 127 struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
128 struct nsproxy *new_ns; 128 struct nsproxy *new_ns;
129 int err = 0;
130 129
131 if (!old_ns) 130 if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
131 CLONE_NEWPID | CLONE_NEWNET)))) {
132 get_nsproxy(old_ns);
132 return 0; 133 return 0;
133
134 get_nsproxy(old_ns);
135
136 if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
137 CLONE_NEWPID | CLONE_NEWNET)))
138 return 0;
139
140 if (!ns_capable(user_ns, CAP_SYS_ADMIN)) {
141 err = -EPERM;
142 goto out;
143 } 134 }
144 135
136 if (!ns_capable(user_ns, CAP_SYS_ADMIN))
137 return -EPERM;
138
145 /* 139 /*
146 * CLONE_NEWIPC must detach from the undolist: after switching 140 * CLONE_NEWIPC must detach from the undolist: after switching
147 * to a new ipc namespace, the semaphore arrays from the old 141 * to a new ipc namespace, the semaphore arrays from the old
@@ -149,22 +143,16 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
149 * means share undolist with parent, so we must forbid using 143 * means share undolist with parent, so we must forbid using
150 * it along with CLONE_NEWIPC. 144 * it along with CLONE_NEWIPC.
151 */ 145 */
152 if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) { 146 if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==
153 err = -EINVAL; 147 (CLONE_NEWIPC | CLONE_SYSVSEM))
154 goto out; 148 return -EINVAL;
155 }
156 149
157 new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); 150 new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
158 if (IS_ERR(new_ns)) { 151 if (IS_ERR(new_ns))
159 err = PTR_ERR(new_ns); 152 return PTR_ERR(new_ns);
160 goto out;
161 }
162 153
163 tsk->nsproxy = new_ns; 154 tsk->nsproxy = new_ns;
164 155 return 0;
165out:
166 put_nsproxy(old_ns);
167 return err;
168} 156}
169 157
170void free_nsproxy(struct nsproxy *ns) 158void free_nsproxy(struct nsproxy *ns)
diff --git a/kernel/pid.c b/kernel/pid.c
index 66505c1dfc51..ebe5e80b10f8 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -265,6 +265,7 @@ void free_pid(struct pid *pid)
265 struct pid_namespace *ns = upid->ns; 265 struct pid_namespace *ns = upid->ns;
266 hlist_del_rcu(&upid->pid_chain); 266 hlist_del_rcu(&upid->pid_chain);
267 switch(--ns->nr_hashed) { 267 switch(--ns->nr_hashed) {
268 case 2:
268 case 1: 269 case 1:
269 /* When all that is left in the pid namespace 270 /* When all that is left in the pid namespace
270 * is the reaper wake up the reaper. The reaper 271 * is the reaper wake up the reaper. The reaper
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 601bb361c235..42086551a24a 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -329,7 +329,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
329 struct pid_namespace *ancestor, *new = ns; 329 struct pid_namespace *ancestor, *new = ns;
330 330
331 if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) || 331 if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
332 !nsown_capable(CAP_SYS_ADMIN)) 332 !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
333 return -EPERM; 333 return -EPERM;
334 334
335 /* 335 /*
diff --git a/kernel/sys.c b/kernel/sys.c
index 771129b299f8..c18ecca575b4 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -337,7 +337,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
337 if (rgid != (gid_t) -1) { 337 if (rgid != (gid_t) -1) {
338 if (gid_eq(old->gid, krgid) || 338 if (gid_eq(old->gid, krgid) ||
339 gid_eq(old->egid, krgid) || 339 gid_eq(old->egid, krgid) ||
340 nsown_capable(CAP_SETGID)) 340 ns_capable(old->user_ns, CAP_SETGID))
341 new->gid = krgid; 341 new->gid = krgid;
342 else 342 else
343 goto error; 343 goto error;
@@ -346,7 +346,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
346 if (gid_eq(old->gid, kegid) || 346 if (gid_eq(old->gid, kegid) ||
347 gid_eq(old->egid, kegid) || 347 gid_eq(old->egid, kegid) ||
348 gid_eq(old->sgid, kegid) || 348 gid_eq(old->sgid, kegid) ||
349 nsown_capable(CAP_SETGID)) 349 ns_capable(old->user_ns, CAP_SETGID))
350 new->egid = kegid; 350 new->egid = kegid;
351 else 351 else
352 goto error; 352 goto error;
@@ -387,7 +387,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
387 old = current_cred(); 387 old = current_cred();
388 388
389 retval = -EPERM; 389 retval = -EPERM;
390 if (nsown_capable(CAP_SETGID)) 390 if (ns_capable(old->user_ns, CAP_SETGID))
391 new->gid = new->egid = new->sgid = new->fsgid = kgid; 391 new->gid = new->egid = new->sgid = new->fsgid = kgid;
392 else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) 392 else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
393 new->egid = new->fsgid = kgid; 393 new->egid = new->fsgid = kgid;
@@ -471,7 +471,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
471 new->uid = kruid; 471 new->uid = kruid;
472 if (!uid_eq(old->uid, kruid) && 472 if (!uid_eq(old->uid, kruid) &&
473 !uid_eq(old->euid, kruid) && 473 !uid_eq(old->euid, kruid) &&
474 !nsown_capable(CAP_SETUID)) 474 !ns_capable(old->user_ns, CAP_SETUID))
475 goto error; 475 goto error;
476 } 476 }
477 477
@@ -480,7 +480,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
480 if (!uid_eq(old->uid, keuid) && 480 if (!uid_eq(old->uid, keuid) &&
481 !uid_eq(old->euid, keuid) && 481 !uid_eq(old->euid, keuid) &&
482 !uid_eq(old->suid, keuid) && 482 !uid_eq(old->suid, keuid) &&
483 !nsown_capable(CAP_SETUID)) 483 !ns_capable(old->user_ns, CAP_SETUID))
484 goto error; 484 goto error;
485 } 485 }
486 486
@@ -534,7 +534,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
534 old = current_cred(); 534 old = current_cred();
535 535
536 retval = -EPERM; 536 retval = -EPERM;
537 if (nsown_capable(CAP_SETUID)) { 537 if (ns_capable(old->user_ns, CAP_SETUID)) {
538 new->suid = new->uid = kuid; 538 new->suid = new->uid = kuid;
539 if (!uid_eq(kuid, old->uid)) { 539 if (!uid_eq(kuid, old->uid)) {
540 retval = set_user(new); 540 retval = set_user(new);
@@ -591,7 +591,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
591 old = current_cred(); 591 old = current_cred();
592 592
593 retval = -EPERM; 593 retval = -EPERM;
594 if (!nsown_capable(CAP_SETUID)) { 594 if (!ns_capable(old->user_ns, CAP_SETUID)) {
595 if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && 595 if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) &&
596 !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) 596 !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
597 goto error; 597 goto error;
@@ -673,7 +673,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
673 old = current_cred(); 673 old = current_cred();
674 674
675 retval = -EPERM; 675 retval = -EPERM;
676 if (!nsown_capable(CAP_SETGID)) { 676 if (!ns_capable(old->user_ns, CAP_SETGID)) {
677 if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && 677 if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) &&
678 !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) 678 !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
679 goto error; 679 goto error;
@@ -744,7 +744,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
744 744
745 if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || 745 if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) ||
746 uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || 746 uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
747 nsown_capable(CAP_SETUID)) { 747 ns_capable(old->user_ns, CAP_SETUID)) {
748 if (!uid_eq(kuid, old->fsuid)) { 748 if (!uid_eq(kuid, old->fsuid)) {
749 new->fsuid = kuid; 749 new->fsuid = kuid;
750 if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) 750 if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
@@ -783,7 +783,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
783 783
784 if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || 784 if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) ||
785 gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || 785 gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
786 nsown_capable(CAP_SETGID)) { 786 ns_capable(old->user_ns, CAP_SETGID)) {
787 if (!gid_eq(kgid, old->fsgid)) { 787 if (!gid_eq(kgid, old->fsgid)) {
788 new->fsgid = kgid; 788 new->fsgid = kgid;
789 goto change_okay; 789 goto change_okay;
diff --git a/kernel/uid16.c b/kernel/uid16.c
index f6c83d7ef000..602e5bbbceff 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
176 struct group_info *group_info; 176 struct group_info *group_info;
177 int retval; 177 int retval;
178 178
179 if (!nsown_capable(CAP_SETGID)) 179 if (!ns_capable(current_user_ns(), CAP_SETGID))
180 return -EPERM; 180 return -EPERM;
181 if ((unsigned)gidsetsize > NGROUPS_MAX) 181 if ((unsigned)gidsetsize > NGROUPS_MAX)
182 return -EINVAL; 182 return -EINVAL;
diff --git a/kernel/user.c b/kernel/user.c
index 69b4c3d48cde..5bbb91988e69 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -51,8 +51,6 @@ struct user_namespace init_user_ns = {
51 .owner = GLOBAL_ROOT_UID, 51 .owner = GLOBAL_ROOT_UID,
52 .group = GLOBAL_ROOT_GID, 52 .group = GLOBAL_ROOT_GID,
53 .proc_inum = PROC_USER_INIT_INO, 53 .proc_inum = PROC_USER_INIT_INO,
54 .may_mount_sysfs = true,
55 .may_mount_proc = true,
56}; 54};
57EXPORT_SYMBOL_GPL(init_user_ns); 55EXPORT_SYMBOL_GPL(init_user_ns);
58 56
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 9064b919a406..13fb1134ba58 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -101,8 +101,6 @@ int create_user_ns(struct cred *new)
101 101
102 set_cred_user_ns(new, ns); 102 set_cred_user_ns(new, ns);
103 103
104 update_mnt_policy(ns);
105
106 return 0; 104 return 0;
107} 105}
108 106
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 2fc8576efaa8..fd393124e507 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -114,7 +114,7 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
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 !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
118 return -EPERM; 118 return -EPERM;
119 119
120 get_uts_ns(ns); 120 get_uts_ns(ns);