diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 86 |
1 files changed, 56 insertions, 30 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 18da702ec813..e4128b278f23 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 | } |
@@ -296,8 +314,9 @@ void kernel_restart_prepare(char *cmd) | |||
296 | { | 314 | { |
297 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); | 315 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); |
298 | system_state = SYSTEM_RESTART; | 316 | system_state = SYSTEM_RESTART; |
317 | usermodehelper_disable(); | ||
299 | device_shutdown(); | 318 | device_shutdown(); |
300 | sysdev_shutdown(); | 319 | syscore_shutdown(); |
301 | } | 320 | } |
302 | 321 | ||
303 | /** | 322 | /** |
@@ -325,6 +344,7 @@ static void kernel_shutdown_prepare(enum system_states state) | |||
325 | blocking_notifier_call_chain(&reboot_notifier_list, | 344 | blocking_notifier_call_chain(&reboot_notifier_list, |
326 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); | 345 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); |
327 | system_state = state; | 346 | system_state = state; |
347 | usermodehelper_disable(); | ||
328 | device_shutdown(); | 348 | device_shutdown(); |
329 | } | 349 | } |
330 | /** | 350 | /** |
@@ -335,7 +355,7 @@ static void kernel_shutdown_prepare(enum system_states state) | |||
335 | void kernel_halt(void) | 355 | void kernel_halt(void) |
336 | { | 356 | { |
337 | kernel_shutdown_prepare(SYSTEM_HALT); | 357 | kernel_shutdown_prepare(SYSTEM_HALT); |
338 | 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(); |
@@ -354,7 +374,7 @@ void kernel_power_off(void) | |||
354 | if (pm_power_off_prepare) | 374 | if (pm_power_off_prepare) |
355 | pm_power_off_prepare(); | 375 | pm_power_off_prepare(); |
356 | disable_nonboot_cpus(); | 376 | disable_nonboot_cpus(); |
357 | sysdev_shutdown(); | 377 | syscore_shutdown(); |
358 | printk(KERN_EMERG "Power down.\n"); | 378 | printk(KERN_EMERG "Power down.\n"); |
359 | kmsg_dump(KMSG_DUMP_POWEROFF); | 379 | kmsg_dump(KMSG_DUMP_POWEROFF); |
360 | machine_power_off(); | 380 | machine_power_off(); |
@@ -502,7 +522,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
502 | if (rgid != (gid_t) -1) { | 522 | if (rgid != (gid_t) -1) { |
503 | if (old->gid == rgid || | 523 | if (old->gid == rgid || |
504 | old->egid == rgid || | 524 | old->egid == rgid || |
505 | capable(CAP_SETGID)) | 525 | nsown_capable(CAP_SETGID)) |
506 | new->gid = rgid; | 526 | new->gid = rgid; |
507 | else | 527 | else |
508 | goto error; | 528 | goto error; |
@@ -511,7 +531,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
511 | if (old->gid == egid || | 531 | if (old->gid == egid || |
512 | old->egid == egid || | 532 | old->egid == egid || |
513 | old->sgid == egid || | 533 | old->sgid == egid || |
514 | capable(CAP_SETGID)) | 534 | nsown_capable(CAP_SETGID)) |
515 | new->egid = egid; | 535 | new->egid = egid; |
516 | else | 536 | else |
517 | goto error; | 537 | goto error; |
@@ -546,7 +566,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
546 | old = current_cred(); | 566 | old = current_cred(); |
547 | 567 | ||
548 | retval = -EPERM; | 568 | retval = -EPERM; |
549 | if (capable(CAP_SETGID)) | 569 | if (nsown_capable(CAP_SETGID)) |
550 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 570 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
551 | else if (gid == old->gid || gid == old->sgid) | 571 | else if (gid == old->gid || gid == old->sgid) |
552 | new->egid = new->fsgid = gid; | 572 | new->egid = new->fsgid = gid; |
@@ -613,7 +633,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
613 | new->uid = ruid; | 633 | new->uid = ruid; |
614 | if (old->uid != ruid && | 634 | if (old->uid != ruid && |
615 | old->euid != ruid && | 635 | old->euid != ruid && |
616 | !capable(CAP_SETUID)) | 636 | !nsown_capable(CAP_SETUID)) |
617 | goto error; | 637 | goto error; |
618 | } | 638 | } |
619 | 639 | ||
@@ -622,7 +642,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
622 | if (old->uid != euid && | 642 | if (old->uid != euid && |
623 | old->euid != euid && | 643 | old->euid != euid && |
624 | old->suid != euid && | 644 | old->suid != euid && |
625 | !capable(CAP_SETUID)) | 645 | !nsown_capable(CAP_SETUID)) |
626 | goto error; | 646 | goto error; |
627 | } | 647 | } |
628 | 648 | ||
@@ -670,7 +690,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
670 | old = current_cred(); | 690 | old = current_cred(); |
671 | 691 | ||
672 | retval = -EPERM; | 692 | retval = -EPERM; |
673 | if (capable(CAP_SETUID)) { | 693 | if (nsown_capable(CAP_SETUID)) { |
674 | new->suid = new->uid = uid; | 694 | new->suid = new->uid = uid; |
675 | if (uid != old->uid) { | 695 | if (uid != old->uid) { |
676 | retval = set_user(new); | 696 | retval = set_user(new); |
@@ -712,7 +732,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
712 | old = current_cred(); | 732 | old = current_cred(); |
713 | 733 | ||
714 | retval = -EPERM; | 734 | retval = -EPERM; |
715 | if (!capable(CAP_SETUID)) { | 735 | if (!nsown_capable(CAP_SETUID)) { |
716 | if (ruid != (uid_t) -1 && ruid != old->uid && | 736 | if (ruid != (uid_t) -1 && ruid != old->uid && |
717 | ruid != old->euid && ruid != old->suid) | 737 | ruid != old->euid && ruid != old->suid) |
718 | goto error; | 738 | goto error; |
@@ -776,7 +796,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
776 | old = current_cred(); | 796 | old = current_cred(); |
777 | 797 | ||
778 | retval = -EPERM; | 798 | retval = -EPERM; |
779 | if (!capable(CAP_SETGID)) { | 799 | if (!nsown_capable(CAP_SETGID)) { |
780 | if (rgid != (gid_t) -1 && rgid != old->gid && | 800 | if (rgid != (gid_t) -1 && rgid != old->gid && |
781 | rgid != old->egid && rgid != old->sgid) | 801 | rgid != old->egid && rgid != old->sgid) |
782 | goto error; | 802 | goto error; |
@@ -836,7 +856,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
836 | 856 | ||
837 | if (uid == old->uid || uid == old->euid || | 857 | if (uid == old->uid || uid == old->euid || |
838 | uid == old->suid || uid == old->fsuid || | 858 | uid == old->suid || uid == old->fsuid || |
839 | capable(CAP_SETUID)) { | 859 | nsown_capable(CAP_SETUID)) { |
840 | if (uid != old_fsuid) { | 860 | if (uid != old_fsuid) { |
841 | new->fsuid = uid; | 861 | new->fsuid = uid; |
842 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 862 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
@@ -869,7 +889,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
869 | 889 | ||
870 | if (gid == old->gid || gid == old->egid || | 890 | if (gid == old->gid || gid == old->egid || |
871 | gid == old->sgid || gid == old->fsgid || | 891 | gid == old->sgid || gid == old->fsgid || |
872 | capable(CAP_SETGID)) { | 892 | nsown_capable(CAP_SETGID)) { |
873 | if (gid != old_fsgid) { | 893 | if (gid != old_fsgid) { |
874 | new->fsgid = gid; | 894 | new->fsgid = gid; |
875 | goto change_okay; | 895 | goto change_okay; |
@@ -1177,8 +1197,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1177 | int errno; | 1197 | int errno; |
1178 | char tmp[__NEW_UTS_LEN]; | 1198 | char tmp[__NEW_UTS_LEN]; |
1179 | 1199 | ||
1180 | if (!capable(CAP_SYS_ADMIN)) | 1200 | if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) |
1181 | return -EPERM; | 1201 | return -EPERM; |
1202 | |||
1182 | if (len < 0 || len > __NEW_UTS_LEN) | 1203 | if (len < 0 || len > __NEW_UTS_LEN) |
1183 | return -EINVAL; | 1204 | return -EINVAL; |
1184 | down_write(&uts_sem); | 1205 | down_write(&uts_sem); |
@@ -1226,7 +1247,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1226 | int errno; | 1247 | int errno; |
1227 | char tmp[__NEW_UTS_LEN]; | 1248 | char tmp[__NEW_UTS_LEN]; |
1228 | 1249 | ||
1229 | if (!capable(CAP_SYS_ADMIN)) | 1250 | if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) |
1230 | return -EPERM; | 1251 | return -EPERM; |
1231 | if (len < 0 || len > __NEW_UTS_LEN) | 1252 | if (len < 0 || len > __NEW_UTS_LEN) |
1232 | return -EINVAL; | 1253 | return -EINVAL; |
@@ -1341,6 +1362,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, | |||
1341 | rlim = tsk->signal->rlim + resource; | 1362 | rlim = tsk->signal->rlim + resource; |
1342 | task_lock(tsk->group_leader); | 1363 | task_lock(tsk->group_leader); |
1343 | if (new_rlim) { | 1364 | if (new_rlim) { |
1365 | /* Keep the capable check against init_user_ns until | ||
1366 | cgroups can contain all limits */ | ||
1344 | if (new_rlim->rlim_max > rlim->rlim_max && | 1367 | if (new_rlim->rlim_max > rlim->rlim_max && |
1345 | !capable(CAP_SYS_RESOURCE)) | 1368 | !capable(CAP_SYS_RESOURCE)) |
1346 | retval = -EPERM; | 1369 | retval = -EPERM; |
@@ -1384,19 +1407,22 @@ static int check_prlimit_permission(struct task_struct *task) | |||
1384 | { | 1407 | { |
1385 | const struct cred *cred = current_cred(), *tcred; | 1408 | const struct cred *cred = current_cred(), *tcred; |
1386 | 1409 | ||
1387 | tcred = __task_cred(task); | 1410 | if (current == task) |
1388 | if (current != task && | 1411 | return 0; |
1389 | (cred->uid != tcred->euid || | ||
1390 | cred->uid != tcred->suid || | ||
1391 | cred->uid != tcred->uid || | ||
1392 | cred->gid != tcred->egid || | ||
1393 | cred->gid != tcred->sgid || | ||
1394 | cred->gid != tcred->gid) && | ||
1395 | !capable(CAP_SYS_RESOURCE)) { | ||
1396 | return -EPERM; | ||
1397 | } | ||
1398 | 1412 | ||
1399 | return 0; | 1413 | tcred = __task_cred(task); |
1414 | if (cred->user->user_ns == tcred->user->user_ns && | ||
1415 | (cred->uid == tcred->euid && | ||
1416 | cred->uid == tcred->suid && | ||
1417 | cred->uid == tcred->uid && | ||
1418 | cred->gid == tcred->egid && | ||
1419 | cred->gid == tcred->sgid && | ||
1420 | cred->gid == tcred->gid)) | ||
1421 | return 0; | ||
1422 | if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE)) | ||
1423 | return 0; | ||
1424 | |||
1425 | return -EPERM; | ||
1400 | } | 1426 | } |
1401 | 1427 | ||
1402 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | 1428 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, |