diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 80 |
1 files changed, 54 insertions, 26 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 31b71a276b40..af468edf096a 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/ptrace.h> | 37 | #include <linux/ptrace.h> |
38 | #include <linux/fs_struct.h> | 38 | #include <linux/fs_struct.h> |
39 | #include <linux/gfp.h> | 39 | #include <linux/gfp.h> |
40 | #include <linux/syscore_ops.h> | ||
40 | 41 | ||
41 | #include <linux/compat.h> | 42 | #include <linux/compat.h> |
42 | #include <linux/syscalls.h> | 43 | #include <linux/syscalls.h> |
@@ -119,16 +120,33 @@ EXPORT_SYMBOL(cad_pid); | |||
119 | void (*pm_power_off_prepare)(void); | 120 | void (*pm_power_off_prepare)(void); |
120 | 121 | ||
121 | /* | 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 | /* | ||
122 | * set the priority of a task | 142 | * set the priority of a task |
123 | * - the caller must hold the RCU read lock | 143 | * - the caller must hold the RCU read lock |
124 | */ | 144 | */ |
125 | 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) |
126 | { | 146 | { |
127 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | ||
128 | int no_nice; | 147 | int no_nice; |
129 | 148 | ||
130 | if (pcred->uid != cred->euid && | 149 | if (!set_one_prio_perm(p)) { |
131 | pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) { | ||
132 | error = -EPERM; | 150 | error = -EPERM; |
133 | goto out; | 151 | goto out; |
134 | } | 152 | } |
@@ -298,6 +316,7 @@ void kernel_restart_prepare(char *cmd) | |||
298 | system_state = SYSTEM_RESTART; | 316 | system_state = SYSTEM_RESTART; |
299 | device_shutdown(); | 317 | device_shutdown(); |
300 | sysdev_shutdown(); | 318 | sysdev_shutdown(); |
319 | syscore_shutdown(); | ||
301 | } | 320 | } |
302 | 321 | ||
303 | /** | 322 | /** |
@@ -336,6 +355,7 @@ void kernel_halt(void) | |||
336 | { | 355 | { |
337 | kernel_shutdown_prepare(SYSTEM_HALT); | 356 | kernel_shutdown_prepare(SYSTEM_HALT); |
338 | sysdev_shutdown(); | 357 | sysdev_shutdown(); |
358 | syscore_shutdown(); | ||
339 | printk(KERN_EMERG "System halted.\n"); | 359 | printk(KERN_EMERG "System halted.\n"); |
340 | kmsg_dump(KMSG_DUMP_HALT); | 360 | kmsg_dump(KMSG_DUMP_HALT); |
341 | machine_halt(); | 361 | machine_halt(); |
@@ -355,6 +375,7 @@ void kernel_power_off(void) | |||
355 | pm_power_off_prepare(); | 375 | pm_power_off_prepare(); |
356 | disable_nonboot_cpus(); | 376 | disable_nonboot_cpus(); |
357 | sysdev_shutdown(); | 377 | sysdev_shutdown(); |
378 | syscore_shutdown(); | ||
358 | printk(KERN_EMERG "Power down.\n"); | 379 | printk(KERN_EMERG "Power down.\n"); |
359 | kmsg_dump(KMSG_DUMP_POWEROFF); | 380 | kmsg_dump(KMSG_DUMP_POWEROFF); |
360 | machine_power_off(); | 381 | machine_power_off(); |
@@ -502,7 +523,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
502 | if (rgid != (gid_t) -1) { | 523 | if (rgid != (gid_t) -1) { |
503 | if (old->gid == rgid || | 524 | if (old->gid == rgid || |
504 | old->egid == rgid || | 525 | old->egid == rgid || |
505 | capable(CAP_SETGID)) | 526 | nsown_capable(CAP_SETGID)) |
506 | new->gid = rgid; | 527 | new->gid = rgid; |
507 | else | 528 | else |
508 | goto error; | 529 | goto error; |
@@ -511,7 +532,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
511 | if (old->gid == egid || | 532 | if (old->gid == egid || |
512 | old->egid == egid || | 533 | old->egid == egid || |
513 | old->sgid == egid || | 534 | old->sgid == egid || |
514 | capable(CAP_SETGID)) | 535 | nsown_capable(CAP_SETGID)) |
515 | new->egid = egid; | 536 | new->egid = egid; |
516 | else | 537 | else |
517 | goto error; | 538 | goto error; |
@@ -546,7 +567,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
546 | old = current_cred(); | 567 | old = current_cred(); |
547 | 568 | ||
548 | retval = -EPERM; | 569 | retval = -EPERM; |
549 | if (capable(CAP_SETGID)) | 570 | if (nsown_capable(CAP_SETGID)) |
550 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 571 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
551 | else if (gid == old->gid || gid == old->sgid) | 572 | else if (gid == old->gid || gid == old->sgid) |
552 | new->egid = new->fsgid = gid; | 573 | new->egid = new->fsgid = gid; |
@@ -613,7 +634,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
613 | new->uid = ruid; | 634 | new->uid = ruid; |
614 | if (old->uid != ruid && | 635 | if (old->uid != ruid && |
615 | old->euid != ruid && | 636 | old->euid != ruid && |
616 | !capable(CAP_SETUID)) | 637 | !nsown_capable(CAP_SETUID)) |
617 | goto error; | 638 | goto error; |
618 | } | 639 | } |
619 | 640 | ||
@@ -622,7 +643,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
622 | if (old->uid != euid && | 643 | if (old->uid != euid && |
623 | old->euid != euid && | 644 | old->euid != euid && |
624 | old->suid != euid && | 645 | old->suid != euid && |
625 | !capable(CAP_SETUID)) | 646 | !nsown_capable(CAP_SETUID)) |
626 | goto error; | 647 | goto error; |
627 | } | 648 | } |
628 | 649 | ||
@@ -670,7 +691,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
670 | old = current_cred(); | 691 | old = current_cred(); |
671 | 692 | ||
672 | retval = -EPERM; | 693 | retval = -EPERM; |
673 | if (capable(CAP_SETUID)) { | 694 | if (nsown_capable(CAP_SETUID)) { |
674 | new->suid = new->uid = uid; | 695 | new->suid = new->uid = uid; |
675 | if (uid != old->uid) { | 696 | if (uid != old->uid) { |
676 | retval = set_user(new); | 697 | retval = set_user(new); |
@@ -712,7 +733,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
712 | old = current_cred(); | 733 | old = current_cred(); |
713 | 734 | ||
714 | retval = -EPERM; | 735 | retval = -EPERM; |
715 | if (!capable(CAP_SETUID)) { | 736 | if (!nsown_capable(CAP_SETUID)) { |
716 | if (ruid != (uid_t) -1 && ruid != old->uid && | 737 | if (ruid != (uid_t) -1 && ruid != old->uid && |
717 | ruid != old->euid && ruid != old->suid) | 738 | ruid != old->euid && ruid != old->suid) |
718 | goto error; | 739 | goto error; |
@@ -776,7 +797,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
776 | old = current_cred(); | 797 | old = current_cred(); |
777 | 798 | ||
778 | retval = -EPERM; | 799 | retval = -EPERM; |
779 | if (!capable(CAP_SETGID)) { | 800 | if (!nsown_capable(CAP_SETGID)) { |
780 | if (rgid != (gid_t) -1 && rgid != old->gid && | 801 | if (rgid != (gid_t) -1 && rgid != old->gid && |
781 | rgid != old->egid && rgid != old->sgid) | 802 | rgid != old->egid && rgid != old->sgid) |
782 | goto error; | 803 | goto error; |
@@ -836,7 +857,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
836 | 857 | ||
837 | if (uid == old->uid || uid == old->euid || | 858 | if (uid == old->uid || uid == old->euid || |
838 | uid == old->suid || uid == old->fsuid || | 859 | uid == old->suid || uid == old->fsuid || |
839 | capable(CAP_SETUID)) { | 860 | nsown_capable(CAP_SETUID)) { |
840 | if (uid != old_fsuid) { | 861 | if (uid != old_fsuid) { |
841 | new->fsuid = uid; | 862 | new->fsuid = uid; |
842 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 863 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
@@ -869,7 +890,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
869 | 890 | ||
870 | if (gid == old->gid || gid == old->egid || | 891 | if (gid == old->gid || gid == old->egid || |
871 | gid == old->sgid || gid == old->fsgid || | 892 | gid == old->sgid || gid == old->fsgid || |
872 | capable(CAP_SETGID)) { | 893 | nsown_capable(CAP_SETGID)) { |
873 | if (gid != old_fsgid) { | 894 | if (gid != old_fsgid) { |
874 | new->fsgid = gid; | 895 | new->fsgid = gid; |
875 | goto change_okay; | 896 | goto change_okay; |
@@ -1177,8 +1198,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1177 | int errno; | 1198 | int errno; |
1178 | char tmp[__NEW_UTS_LEN]; | 1199 | char tmp[__NEW_UTS_LEN]; |
1179 | 1200 | ||
1180 | if (!capable(CAP_SYS_ADMIN)) | 1201 | if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) |
1181 | return -EPERM; | 1202 | return -EPERM; |
1203 | |||
1182 | if (len < 0 || len > __NEW_UTS_LEN) | 1204 | if (len < 0 || len > __NEW_UTS_LEN) |
1183 | return -EINVAL; | 1205 | return -EINVAL; |
1184 | down_write(&uts_sem); | 1206 | down_write(&uts_sem); |
@@ -1226,7 +1248,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1226 | int errno; | 1248 | int errno; |
1227 | char tmp[__NEW_UTS_LEN]; | 1249 | char tmp[__NEW_UTS_LEN]; |
1228 | 1250 | ||
1229 | if (!capable(CAP_SYS_ADMIN)) | 1251 | if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) |
1230 | return -EPERM; | 1252 | return -EPERM; |
1231 | if (len < 0 || len > __NEW_UTS_LEN) | 1253 | if (len < 0 || len > __NEW_UTS_LEN) |
1232 | return -EINVAL; | 1254 | return -EINVAL; |
@@ -1341,6 +1363,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, | |||
1341 | rlim = tsk->signal->rlim + resource; | 1363 | rlim = tsk->signal->rlim + resource; |
1342 | task_lock(tsk->group_leader); | 1364 | task_lock(tsk->group_leader); |
1343 | if (new_rlim) { | 1365 | if (new_rlim) { |
1366 | /* Keep the capable check against init_user_ns until | ||
1367 | cgroups can contain all limits */ | ||
1344 | if (new_rlim->rlim_max > rlim->rlim_max && | 1368 | if (new_rlim->rlim_max > rlim->rlim_max && |
1345 | !capable(CAP_SYS_RESOURCE)) | 1369 | !capable(CAP_SYS_RESOURCE)) |
1346 | retval = -EPERM; | 1370 | retval = -EPERM; |
@@ -1384,18 +1408,22 @@ static int check_prlimit_permission(struct task_struct *task) | |||
1384 | { | 1408 | { |
1385 | const struct cred *cred = current_cred(), *tcred; | 1409 | const struct cred *cred = current_cred(), *tcred; |
1386 | 1410 | ||
1387 | tcred = __task_cred(task); | 1411 | if (current == task) |
1388 | if ((cred->uid != tcred->euid || | 1412 | return 0; |
1389 | cred->uid != tcred->suid || | ||
1390 | cred->uid != tcred->uid || | ||
1391 | cred->gid != tcred->egid || | ||
1392 | cred->gid != tcred->sgid || | ||
1393 | cred->gid != tcred->gid) && | ||
1394 | !capable(CAP_SYS_RESOURCE)) { | ||
1395 | return -EPERM; | ||
1396 | } | ||
1397 | 1413 | ||
1398 | 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; | ||
1399 | } | 1427 | } |
1400 | 1428 | ||
1401 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | 1429 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, |