aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
authorSerge E. Hallyn <serge@hallyn.com>2011-03-23 19:43:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-23 22:47:06 -0400
commitfc832ad3645f0507f24d11752544525a50a83c71 (patch)
treed02dd477d94cdeaa42286dbeffcb60467fb30fb7 /kernel/sys.c
parent3263245de48344ad7bdd0e7256bf1606d2592f88 (diff)
userns: user namespaces: convert all capable checks in kernel/sys.c
This allows setuid/setgid in containers. It also fixes some corner cases where kernel logic foregoes capability checks when uids are equivalent. The latter will need to be done throughout the whole kernel. Changelog: Jan 11: Use nsown_capable() as suggested by Bastian Blank. Jan 11: Fix logic errors in uid checks pointed out by Bastian. Feb 15: allow prlimit to current (was regression in previous version) Feb 23: remove debugging printks, uninline set_one_prio_perm and make it bool, and document its return value. Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com> Acked-by: Daniel Lezcano <daniel.lezcano@free.fr> Acked-by: David Howells <dhowells@redhat.com> Cc: James Morris <jmorris@namei.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c75
1 files changed, 49 insertions, 26 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index 5761c53e19e3..af468edf096a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -120,16 +120,33 @@ EXPORT_SYMBOL(cad_pid);
120void (*pm_power_off_prepare)(void); 120void (*pm_power_off_prepare)(void);
121 121
122/* 122/*
123 * Returns true if current's euid is same as p's uid or euid,
124 * or has CAP_SYS_NICE to p's user_ns.
125 *
126 * Called with rcu_read_lock, creds are safe
127 */
128static bool set_one_prio_perm(struct task_struct *p)
129{
130 const struct cred *cred = current_cred(), *pcred = __task_cred(p);
131
132 if (pcred->user->user_ns == cred->user->user_ns &&
133 (pcred->uid == cred->euid ||
134 pcred->euid == cred->euid))
135 return true;
136 if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
137 return true;
138 return false;
139}
140
141/*
123 * set the priority of a task 142 * set the priority of a task
124 * - the caller must hold the RCU read lock 143 * - the caller must hold the RCU read lock
125 */ 144 */
126static int set_one_prio(struct task_struct *p, int niceval, int error) 145static int set_one_prio(struct task_struct *p, int niceval, int error)
127{ 146{
128 const struct cred *cred = current_cred(), *pcred = __task_cred(p);
129 int no_nice; 147 int no_nice;
130 148
131 if (pcred->uid != cred->euid && 149 if (!set_one_prio_perm(p)) {
132 pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
133 error = -EPERM; 150 error = -EPERM;
134 goto out; 151 goto out;
135 } 152 }
@@ -506,7 +523,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
506 if (rgid != (gid_t) -1) { 523 if (rgid != (gid_t) -1) {
507 if (old->gid == rgid || 524 if (old->gid == rgid ||
508 old->egid == rgid || 525 old->egid == rgid ||
509 capable(CAP_SETGID)) 526 nsown_capable(CAP_SETGID))
510 new->gid = rgid; 527 new->gid = rgid;
511 else 528 else
512 goto error; 529 goto error;
@@ -515,7 +532,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
515 if (old->gid == egid || 532 if (old->gid == egid ||
516 old->egid == egid || 533 old->egid == egid ||
517 old->sgid == egid || 534 old->sgid == egid ||
518 capable(CAP_SETGID)) 535 nsown_capable(CAP_SETGID))
519 new->egid = egid; 536 new->egid = egid;
520 else 537 else
521 goto error; 538 goto error;
@@ -550,7 +567,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
550 old = current_cred(); 567 old = current_cred();
551 568
552 retval = -EPERM; 569 retval = -EPERM;
553 if (capable(CAP_SETGID)) 570 if (nsown_capable(CAP_SETGID))
554 new->gid = new->egid = new->sgid = new->fsgid = gid; 571 new->gid = new->egid = new->sgid = new->fsgid = gid;
555 else if (gid == old->gid || gid == old->sgid) 572 else if (gid == old->gid || gid == old->sgid)
556 new->egid = new->fsgid = gid; 573 new->egid = new->fsgid = gid;
@@ -617,7 +634,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
617 new->uid = ruid; 634 new->uid = ruid;
618 if (old->uid != ruid && 635 if (old->uid != ruid &&
619 old->euid != ruid && 636 old->euid != ruid &&
620 !capable(CAP_SETUID)) 637 !nsown_capable(CAP_SETUID))
621 goto error; 638 goto error;
622 } 639 }
623 640
@@ -626,7 +643,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
626 if (old->uid != euid && 643 if (old->uid != euid &&
627 old->euid != euid && 644 old->euid != euid &&
628 old->suid != euid && 645 old->suid != euid &&
629 !capable(CAP_SETUID)) 646 !nsown_capable(CAP_SETUID))
630 goto error; 647 goto error;
631 } 648 }
632 649
@@ -674,7 +691,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
674 old = current_cred(); 691 old = current_cred();
675 692
676 retval = -EPERM; 693 retval = -EPERM;
677 if (capable(CAP_SETUID)) { 694 if (nsown_capable(CAP_SETUID)) {
678 new->suid = new->uid = uid; 695 new->suid = new->uid = uid;
679 if (uid != old->uid) { 696 if (uid != old->uid) {
680 retval = set_user(new); 697 retval = set_user(new);
@@ -716,7 +733,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
716 old = current_cred(); 733 old = current_cred();
717 734
718 retval = -EPERM; 735 retval = -EPERM;
719 if (!capable(CAP_SETUID)) { 736 if (!nsown_capable(CAP_SETUID)) {
720 if (ruid != (uid_t) -1 && ruid != old->uid && 737 if (ruid != (uid_t) -1 && ruid != old->uid &&
721 ruid != old->euid && ruid != old->suid) 738 ruid != old->euid && ruid != old->suid)
722 goto error; 739 goto error;
@@ -780,7 +797,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
780 old = current_cred(); 797 old = current_cred();
781 798
782 retval = -EPERM; 799 retval = -EPERM;
783 if (!capable(CAP_SETGID)) { 800 if (!nsown_capable(CAP_SETGID)) {
784 if (rgid != (gid_t) -1 && rgid != old->gid && 801 if (rgid != (gid_t) -1 && rgid != old->gid &&
785 rgid != old->egid && rgid != old->sgid) 802 rgid != old->egid && rgid != old->sgid)
786 goto error; 803 goto error;
@@ -840,7 +857,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
840 857
841 if (uid == old->uid || uid == old->euid || 858 if (uid == old->uid || uid == old->euid ||
842 uid == old->suid || uid == old->fsuid || 859 uid == old->suid || uid == old->fsuid ||
843 capable(CAP_SETUID)) { 860 nsown_capable(CAP_SETUID)) {
844 if (uid != old_fsuid) { 861 if (uid != old_fsuid) {
845 new->fsuid = uid; 862 new->fsuid = uid;
846 if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) 863 if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
@@ -873,7 +890,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
873 890
874 if (gid == old->gid || gid == old->egid || 891 if (gid == old->gid || gid == old->egid ||
875 gid == old->sgid || gid == old->fsgid || 892 gid == old->sgid || gid == old->fsgid ||
876 capable(CAP_SETGID)) { 893 nsown_capable(CAP_SETGID)) {
877 if (gid != old_fsgid) { 894 if (gid != old_fsgid) {
878 new->fsgid = gid; 895 new->fsgid = gid;
879 goto change_okay; 896 goto change_okay;
@@ -1183,6 +1200,7 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
1183 1200
1184 if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) 1201 if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
1185 return -EPERM; 1202 return -EPERM;
1203
1186 if (len < 0 || len > __NEW_UTS_LEN) 1204 if (len < 0 || len > __NEW_UTS_LEN)
1187 return -EINVAL; 1205 return -EINVAL;
1188 down_write(&uts_sem); 1206 down_write(&uts_sem);
@@ -1230,7 +1248,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
1230 int errno; 1248 int errno;
1231 char tmp[__NEW_UTS_LEN]; 1249 char tmp[__NEW_UTS_LEN];
1232 1250
1233 if (!capable(CAP_SYS_ADMIN)) 1251 if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
1234 return -EPERM; 1252 return -EPERM;
1235 if (len < 0 || len > __NEW_UTS_LEN) 1253 if (len < 0 || len > __NEW_UTS_LEN)
1236 return -EINVAL; 1254 return -EINVAL;
@@ -1345,6 +1363,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource,
1345 rlim = tsk->signal->rlim + resource; 1363 rlim = tsk->signal->rlim + resource;
1346 task_lock(tsk->group_leader); 1364 task_lock(tsk->group_leader);
1347 if (new_rlim) { 1365 if (new_rlim) {
1366 /* Keep the capable check against init_user_ns until
1367 cgroups can contain all limits */
1348 if (new_rlim->rlim_max > rlim->rlim_max && 1368 if (new_rlim->rlim_max > rlim->rlim_max &&
1349 !capable(CAP_SYS_RESOURCE)) 1369 !capable(CAP_SYS_RESOURCE))
1350 retval = -EPERM; 1370 retval = -EPERM;
@@ -1388,19 +1408,22 @@ static int check_prlimit_permission(struct task_struct *task)
1388{ 1408{
1389 const struct cred *cred = current_cred(), *tcred; 1409 const struct cred *cred = current_cred(), *tcred;
1390 1410
1391 tcred = __task_cred(task); 1411 if (current == task)
1392 if (current != task && 1412 return 0;
1393 (cred->uid != tcred->euid ||
1394 cred->uid != tcred->suid ||
1395 cred->uid != tcred->uid ||
1396 cred->gid != tcred->egid ||
1397 cred->gid != tcred->sgid ||
1398 cred->gid != tcred->gid) &&
1399 !capable(CAP_SYS_RESOURCE)) {
1400 return -EPERM;
1401 }
1402 1413
1403 return 0; 1414 tcred = __task_cred(task);
1415 if (cred->user->user_ns == tcred->user->user_ns &&
1416 (cred->uid == tcred->euid &&
1417 cred->uid == tcred->suid &&
1418 cred->uid == tcred->uid &&
1419 cred->gid == tcred->egid &&
1420 cred->gid == tcred->sgid &&
1421 cred->gid == tcred->gid))
1422 return 0;
1423 if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
1424 return 0;
1425
1426 return -EPERM;
1404} 1427}
1405 1428
1406SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, 1429SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource,