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, |
