diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 95 |
1 files changed, 65 insertions, 30 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 7f5a0cd296a9..e4128b278f23 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -37,12 +37,15 @@ | |||
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> |
43 | #include <linux/kprobes.h> | 44 | #include <linux/kprobes.h> |
44 | #include <linux/user_namespace.h> | 45 | #include <linux/user_namespace.h> |
45 | 46 | ||
47 | #include <linux/kmsg_dump.h> | ||
48 | |||
46 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
47 | #include <asm/io.h> | 50 | #include <asm/io.h> |
48 | #include <asm/unistd.h> | 51 | #include <asm/unistd.h> |
@@ -117,16 +120,33 @@ EXPORT_SYMBOL(cad_pid); | |||
117 | void (*pm_power_off_prepare)(void); | 120 | void (*pm_power_off_prepare)(void); |
118 | 121 | ||
119 | /* | 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 | /* | ||
120 | * set the priority of a task | 142 | * set the priority of a task |
121 | * - the caller must hold the RCU read lock | 143 | * - the caller must hold the RCU read lock |
122 | */ | 144 | */ |
123 | 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) |
124 | { | 146 | { |
125 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | ||
126 | int no_nice; | 147 | int no_nice; |
127 | 148 | ||
128 | if (pcred->uid != cred->euid && | 149 | if (!set_one_prio_perm(p)) { |
129 | pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) { | ||
130 | error = -EPERM; | 150 | error = -EPERM; |
131 | goto out; | 151 | goto out; |
132 | } | 152 | } |
@@ -285,6 +305,7 @@ out_unlock: | |||
285 | */ | 305 | */ |
286 | void emergency_restart(void) | 306 | void emergency_restart(void) |
287 | { | 307 | { |
308 | kmsg_dump(KMSG_DUMP_EMERG); | ||
288 | machine_emergency_restart(); | 309 | machine_emergency_restart(); |
289 | } | 310 | } |
290 | EXPORT_SYMBOL_GPL(emergency_restart); | 311 | EXPORT_SYMBOL_GPL(emergency_restart); |
@@ -293,8 +314,9 @@ void kernel_restart_prepare(char *cmd) | |||
293 | { | 314 | { |
294 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); | 315 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); |
295 | system_state = SYSTEM_RESTART; | 316 | system_state = SYSTEM_RESTART; |
317 | usermodehelper_disable(); | ||
296 | device_shutdown(); | 318 | device_shutdown(); |
297 | sysdev_shutdown(); | 319 | syscore_shutdown(); |
298 | } | 320 | } |
299 | 321 | ||
300 | /** | 322 | /** |
@@ -312,6 +334,7 @@ void kernel_restart(char *cmd) | |||
312 | printk(KERN_EMERG "Restarting system.\n"); | 334 | printk(KERN_EMERG "Restarting system.\n"); |
313 | else | 335 | else |
314 | printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd); | 336 | printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd); |
337 | kmsg_dump(KMSG_DUMP_RESTART); | ||
315 | machine_restart(cmd); | 338 | machine_restart(cmd); |
316 | } | 339 | } |
317 | EXPORT_SYMBOL_GPL(kernel_restart); | 340 | EXPORT_SYMBOL_GPL(kernel_restart); |
@@ -321,6 +344,7 @@ static void kernel_shutdown_prepare(enum system_states state) | |||
321 | blocking_notifier_call_chain(&reboot_notifier_list, | 344 | blocking_notifier_call_chain(&reboot_notifier_list, |
322 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); | 345 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); |
323 | system_state = state; | 346 | system_state = state; |
347 | usermodehelper_disable(); | ||
324 | device_shutdown(); | 348 | device_shutdown(); |
325 | } | 349 | } |
326 | /** | 350 | /** |
@@ -331,8 +355,9 @@ static void kernel_shutdown_prepare(enum system_states state) | |||
331 | void kernel_halt(void) | 355 | void kernel_halt(void) |
332 | { | 356 | { |
333 | kernel_shutdown_prepare(SYSTEM_HALT); | 357 | kernel_shutdown_prepare(SYSTEM_HALT); |
334 | sysdev_shutdown(); | 358 | syscore_shutdown(); |
335 | printk(KERN_EMERG "System halted.\n"); | 359 | printk(KERN_EMERG "System halted.\n"); |
360 | kmsg_dump(KMSG_DUMP_HALT); | ||
336 | machine_halt(); | 361 | machine_halt(); |
337 | } | 362 | } |
338 | 363 | ||
@@ -349,8 +374,9 @@ void kernel_power_off(void) | |||
349 | if (pm_power_off_prepare) | 374 | if (pm_power_off_prepare) |
350 | pm_power_off_prepare(); | 375 | pm_power_off_prepare(); |
351 | disable_nonboot_cpus(); | 376 | disable_nonboot_cpus(); |
352 | sysdev_shutdown(); | 377 | syscore_shutdown(); |
353 | printk(KERN_EMERG "Power down.\n"); | 378 | printk(KERN_EMERG "Power down.\n"); |
379 | kmsg_dump(KMSG_DUMP_POWEROFF); | ||
354 | machine_power_off(); | 380 | machine_power_off(); |
355 | } | 381 | } |
356 | EXPORT_SYMBOL_GPL(kernel_power_off); | 382 | EXPORT_SYMBOL_GPL(kernel_power_off); |
@@ -496,7 +522,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
496 | if (rgid != (gid_t) -1) { | 522 | if (rgid != (gid_t) -1) { |
497 | if (old->gid == rgid || | 523 | if (old->gid == rgid || |
498 | old->egid == rgid || | 524 | old->egid == rgid || |
499 | capable(CAP_SETGID)) | 525 | nsown_capable(CAP_SETGID)) |
500 | new->gid = rgid; | 526 | new->gid = rgid; |
501 | else | 527 | else |
502 | goto error; | 528 | goto error; |
@@ -505,7 +531,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
505 | if (old->gid == egid || | 531 | if (old->gid == egid || |
506 | old->egid == egid || | 532 | old->egid == egid || |
507 | old->sgid == egid || | 533 | old->sgid == egid || |
508 | capable(CAP_SETGID)) | 534 | nsown_capable(CAP_SETGID)) |
509 | new->egid = egid; | 535 | new->egid = egid; |
510 | else | 536 | else |
511 | goto error; | 537 | goto error; |
@@ -540,7 +566,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
540 | old = current_cred(); | 566 | old = current_cred(); |
541 | 567 | ||
542 | retval = -EPERM; | 568 | retval = -EPERM; |
543 | if (capable(CAP_SETGID)) | 569 | if (nsown_capable(CAP_SETGID)) |
544 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 570 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
545 | else if (gid == old->gid || gid == old->sgid) | 571 | else if (gid == old->gid || gid == old->sgid) |
546 | new->egid = new->fsgid = gid; | 572 | new->egid = new->fsgid = gid; |
@@ -607,7 +633,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
607 | new->uid = ruid; | 633 | new->uid = ruid; |
608 | if (old->uid != ruid && | 634 | if (old->uid != ruid && |
609 | old->euid != ruid && | 635 | old->euid != ruid && |
610 | !capable(CAP_SETUID)) | 636 | !nsown_capable(CAP_SETUID)) |
611 | goto error; | 637 | goto error; |
612 | } | 638 | } |
613 | 639 | ||
@@ -616,7 +642,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
616 | if (old->uid != euid && | 642 | if (old->uid != euid && |
617 | old->euid != euid && | 643 | old->euid != euid && |
618 | old->suid != euid && | 644 | old->suid != euid && |
619 | !capable(CAP_SETUID)) | 645 | !nsown_capable(CAP_SETUID)) |
620 | goto error; | 646 | goto error; |
621 | } | 647 | } |
622 | 648 | ||
@@ -664,7 +690,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
664 | old = current_cred(); | 690 | old = current_cred(); |
665 | 691 | ||
666 | retval = -EPERM; | 692 | retval = -EPERM; |
667 | if (capable(CAP_SETUID)) { | 693 | if (nsown_capable(CAP_SETUID)) { |
668 | new->suid = new->uid = uid; | 694 | new->suid = new->uid = uid; |
669 | if (uid != old->uid) { | 695 | if (uid != old->uid) { |
670 | retval = set_user(new); | 696 | retval = set_user(new); |
@@ -706,7 +732,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
706 | old = current_cred(); | 732 | old = current_cred(); |
707 | 733 | ||
708 | retval = -EPERM; | 734 | retval = -EPERM; |
709 | if (!capable(CAP_SETUID)) { | 735 | if (!nsown_capable(CAP_SETUID)) { |
710 | if (ruid != (uid_t) -1 && ruid != old->uid && | 736 | if (ruid != (uid_t) -1 && ruid != old->uid && |
711 | ruid != old->euid && ruid != old->suid) | 737 | ruid != old->euid && ruid != old->suid) |
712 | goto error; | 738 | goto error; |
@@ -770,7 +796,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
770 | old = current_cred(); | 796 | old = current_cred(); |
771 | 797 | ||
772 | retval = -EPERM; | 798 | retval = -EPERM; |
773 | if (!capable(CAP_SETGID)) { | 799 | if (!nsown_capable(CAP_SETGID)) { |
774 | if (rgid != (gid_t) -1 && rgid != old->gid && | 800 | if (rgid != (gid_t) -1 && rgid != old->gid && |
775 | rgid != old->egid && rgid != old->sgid) | 801 | rgid != old->egid && rgid != old->sgid) |
776 | goto error; | 802 | goto error; |
@@ -830,7 +856,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
830 | 856 | ||
831 | if (uid == old->uid || uid == old->euid || | 857 | if (uid == old->uid || uid == old->euid || |
832 | uid == old->suid || uid == old->fsuid || | 858 | uid == old->suid || uid == old->fsuid || |
833 | capable(CAP_SETUID)) { | 859 | nsown_capable(CAP_SETUID)) { |
834 | if (uid != old_fsuid) { | 860 | if (uid != old_fsuid) { |
835 | new->fsuid = uid; | 861 | new->fsuid = uid; |
836 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 862 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) |
@@ -863,7 +889,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
863 | 889 | ||
864 | if (gid == old->gid || gid == old->egid || | 890 | if (gid == old->gid || gid == old->egid || |
865 | gid == old->sgid || gid == old->fsgid || | 891 | gid == old->sgid || gid == old->fsgid || |
866 | capable(CAP_SETGID)) { | 892 | nsown_capable(CAP_SETGID)) { |
867 | if (gid != old_fsgid) { | 893 | if (gid != old_fsgid) { |
868 | new->fsgid = gid; | 894 | new->fsgid = gid; |
869 | goto change_okay; | 895 | goto change_okay; |
@@ -1080,8 +1106,10 @@ SYSCALL_DEFINE0(setsid) | |||
1080 | err = session; | 1106 | err = session; |
1081 | out: | 1107 | out: |
1082 | write_unlock_irq(&tasklist_lock); | 1108 | write_unlock_irq(&tasklist_lock); |
1083 | if (err > 0) | 1109 | if (err > 0) { |
1084 | proc_sid_connector(group_leader); | 1110 | proc_sid_connector(group_leader); |
1111 | sched_autogroup_create_attach(group_leader); | ||
1112 | } | ||
1085 | return err; | 1113 | return err; |
1086 | } | 1114 | } |
1087 | 1115 | ||
@@ -1169,8 +1197,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1169 | int errno; | 1197 | int errno; |
1170 | char tmp[__NEW_UTS_LEN]; | 1198 | char tmp[__NEW_UTS_LEN]; |
1171 | 1199 | ||
1172 | if (!capable(CAP_SYS_ADMIN)) | 1200 | if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) |
1173 | return -EPERM; | 1201 | return -EPERM; |
1202 | |||
1174 | if (len < 0 || len > __NEW_UTS_LEN) | 1203 | if (len < 0 || len > __NEW_UTS_LEN) |
1175 | return -EINVAL; | 1204 | return -EINVAL; |
1176 | down_write(&uts_sem); | 1205 | down_write(&uts_sem); |
@@ -1218,7 +1247,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1218 | int errno; | 1247 | int errno; |
1219 | char tmp[__NEW_UTS_LEN]; | 1248 | char tmp[__NEW_UTS_LEN]; |
1220 | 1249 | ||
1221 | if (!capable(CAP_SYS_ADMIN)) | 1250 | if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) |
1222 | return -EPERM; | 1251 | return -EPERM; |
1223 | if (len < 0 || len > __NEW_UTS_LEN) | 1252 | if (len < 0 || len > __NEW_UTS_LEN) |
1224 | return -EINVAL; | 1253 | return -EINVAL; |
@@ -1333,6 +1362,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource, | |||
1333 | rlim = tsk->signal->rlim + resource; | 1362 | rlim = tsk->signal->rlim + resource; |
1334 | task_lock(tsk->group_leader); | 1363 | task_lock(tsk->group_leader); |
1335 | if (new_rlim) { | 1364 | if (new_rlim) { |
1365 | /* Keep the capable check against init_user_ns until | ||
1366 | cgroups can contain all limits */ | ||
1336 | if (new_rlim->rlim_max > rlim->rlim_max && | 1367 | if (new_rlim->rlim_max > rlim->rlim_max && |
1337 | !capable(CAP_SYS_RESOURCE)) | 1368 | !capable(CAP_SYS_RESOURCE)) |
1338 | retval = -EPERM; | 1369 | retval = -EPERM; |
@@ -1376,18 +1407,22 @@ static int check_prlimit_permission(struct task_struct *task) | |||
1376 | { | 1407 | { |
1377 | const struct cred *cred = current_cred(), *tcred; | 1408 | const struct cred *cred = current_cred(), *tcred; |
1378 | 1409 | ||
1379 | tcred = __task_cred(task); | 1410 | if (current == task) |
1380 | if ((cred->uid != tcred->euid || | 1411 | return 0; |
1381 | cred->uid != tcred->suid || | ||
1382 | cred->uid != tcred->uid || | ||
1383 | cred->gid != tcred->egid || | ||
1384 | cred->gid != tcred->sgid || | ||
1385 | cred->gid != tcred->gid) && | ||
1386 | !capable(CAP_SYS_RESOURCE)) { | ||
1387 | return -EPERM; | ||
1388 | } | ||
1389 | 1412 | ||
1390 | 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; | ||
1391 | } | 1426 | } |
1392 | 1427 | ||
1393 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | 1428 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, |