diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 1ad48b3b9068..af468edf096a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -120,16 +120,33 @@ EXPORT_SYMBOL(cad_pid); | |||
120 | void (*pm_power_off_prepare)(void); | 120 | void (*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 | */ | ||
128 | static 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 | */ |
126 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 145 | static 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; |
@@ -1181,8 +1198,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1181 | int errno; | 1198 | int errno; |
1182 | char tmp[__NEW_UTS_LEN]; | 1199 | char tmp[__NEW_UTS_LEN]; |
1183 | 1200 | ||
1184 | if (!capable(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 | ||
1406 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | 1429 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, |