diff options
author | Paul Mundt <lethal@linux-sh.org> | 2011-01-13 01:06:28 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-01-13 01:06:28 -0500 |
commit | f43dc23d5ea91fca257be02138a255f02d98e806 (patch) | |
tree | b29722f6e965316e90ac97abf79923ced250dc21 /kernel/sys.c | |
parent | f8e53553f452dcbf67cb89c8cba63a1cd6eb4cc0 (diff) | |
parent | 4162cf64973df51fc885825bc9ca4d055891c49f (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6 into common/serial-rework
Conflicts:
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/setup-sh5.c
drivers/serial/sh-sci.c
drivers/serial/sh-sci.h
include/linux/serial_sci.h
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 427 |
1 files changed, 314 insertions, 113 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index b3f1097c76fa..2745dcdb6c6c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -8,13 +8,12 @@ | |||
8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
9 | #include <linux/utsname.h> | 9 | #include <linux/utsname.h> |
10 | #include <linux/mman.h> | 10 | #include <linux/mman.h> |
11 | #include <linux/smp_lock.h> | ||
12 | #include <linux/notifier.h> | 11 | #include <linux/notifier.h> |
13 | #include <linux/reboot.h> | 12 | #include <linux/reboot.h> |
14 | #include <linux/prctl.h> | 13 | #include <linux/prctl.h> |
15 | #include <linux/highuid.h> | 14 | #include <linux/highuid.h> |
16 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
17 | #include <linux/perf_counter.h> | 16 | #include <linux/perf_event.h> |
18 | #include <linux/resource.h> | 17 | #include <linux/resource.h> |
19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
20 | #include <linux/kexec.h> | 19 | #include <linux/kexec.h> |
@@ -34,8 +33,10 @@ | |||
34 | #include <linux/task_io_accounting_ops.h> | 33 | #include <linux/task_io_accounting_ops.h> |
35 | #include <linux/seccomp.h> | 34 | #include <linux/seccomp.h> |
36 | #include <linux/cpu.h> | 35 | #include <linux/cpu.h> |
36 | #include <linux/personality.h> | ||
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 | 40 | ||
40 | #include <linux/compat.h> | 41 | #include <linux/compat.h> |
41 | #include <linux/syscalls.h> | 42 | #include <linux/syscalls.h> |
@@ -163,6 +164,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
163 | if (niceval > 19) | 164 | if (niceval > 19) |
164 | niceval = 19; | 165 | niceval = 19; |
165 | 166 | ||
167 | rcu_read_lock(); | ||
166 | read_lock(&tasklist_lock); | 168 | read_lock(&tasklist_lock); |
167 | switch (which) { | 169 | switch (which) { |
168 | case PRIO_PROCESS: | 170 | case PRIO_PROCESS: |
@@ -190,16 +192,17 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) | |||
190 | !(user = find_user(who))) | 192 | !(user = find_user(who))) |
191 | goto out_unlock; /* No processes for this user */ | 193 | goto out_unlock; /* No processes for this user */ |
192 | 194 | ||
193 | do_each_thread(g, p) | 195 | do_each_thread(g, p) { |
194 | if (__task_cred(p)->uid == who) | 196 | if (__task_cred(p)->uid == who) |
195 | error = set_one_prio(p, niceval, error); | 197 | error = set_one_prio(p, niceval, error); |
196 | while_each_thread(g, p); | 198 | } while_each_thread(g, p); |
197 | if (who != cred->uid) | 199 | if (who != cred->uid) |
198 | free_uid(user); /* For find_user() */ | 200 | free_uid(user); /* For find_user() */ |
199 | break; | 201 | break; |
200 | } | 202 | } |
201 | out_unlock: | 203 | out_unlock: |
202 | read_unlock(&tasklist_lock); | 204 | read_unlock(&tasklist_lock); |
205 | rcu_read_unlock(); | ||
203 | out: | 206 | out: |
204 | return error; | 207 | return error; |
205 | } | 208 | } |
@@ -221,6 +224,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
221 | if (which > PRIO_USER || which < PRIO_PROCESS) | 224 | if (which > PRIO_USER || which < PRIO_PROCESS) |
222 | return -EINVAL; | 225 | return -EINVAL; |
223 | 226 | ||
227 | rcu_read_lock(); | ||
224 | read_lock(&tasklist_lock); | 228 | read_lock(&tasklist_lock); |
225 | switch (which) { | 229 | switch (which) { |
226 | case PRIO_PROCESS: | 230 | case PRIO_PROCESS: |
@@ -253,19 +257,20 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who) | |||
253 | !(user = find_user(who))) | 257 | !(user = find_user(who))) |
254 | goto out_unlock; /* No processes for this user */ | 258 | goto out_unlock; /* No processes for this user */ |
255 | 259 | ||
256 | do_each_thread(g, p) | 260 | do_each_thread(g, p) { |
257 | if (__task_cred(p)->uid == who) { | 261 | if (__task_cred(p)->uid == who) { |
258 | niceval = 20 - task_nice(p); | 262 | niceval = 20 - task_nice(p); |
259 | if (niceval > retval) | 263 | if (niceval > retval) |
260 | retval = niceval; | 264 | retval = niceval; |
261 | } | 265 | } |
262 | while_each_thread(g, p); | 266 | } while_each_thread(g, p); |
263 | if (who != cred->uid) | 267 | if (who != cred->uid) |
264 | free_uid(user); /* for find_user() */ | 268 | free_uid(user); /* for find_user() */ |
265 | break; | 269 | break; |
266 | } | 270 | } |
267 | out_unlock: | 271 | out_unlock: |
268 | read_unlock(&tasklist_lock); | 272 | read_unlock(&tasklist_lock); |
273 | rcu_read_unlock(); | ||
269 | 274 | ||
270 | return retval; | 275 | return retval; |
271 | } | 276 | } |
@@ -349,6 +354,9 @@ void kernel_power_off(void) | |||
349 | machine_power_off(); | 354 | machine_power_off(); |
350 | } | 355 | } |
351 | EXPORT_SYMBOL_GPL(kernel_power_off); | 356 | EXPORT_SYMBOL_GPL(kernel_power_off); |
357 | |||
358 | static DEFINE_MUTEX(reboot_mutex); | ||
359 | |||
352 | /* | 360 | /* |
353 | * Reboot system call: for obvious reasons only root may call it, | 361 | * Reboot system call: for obvious reasons only root may call it, |
354 | * and even root needs to set up some magic numbers in the registers | 362 | * and even root needs to set up some magic numbers in the registers |
@@ -381,7 +389,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, | |||
381 | if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) | 389 | if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) |
382 | cmd = LINUX_REBOOT_CMD_HALT; | 390 | cmd = LINUX_REBOOT_CMD_HALT; |
383 | 391 | ||
384 | lock_kernel(); | 392 | mutex_lock(&reboot_mutex); |
385 | switch (cmd) { | 393 | switch (cmd) { |
386 | case LINUX_REBOOT_CMD_RESTART: | 394 | case LINUX_REBOOT_CMD_RESTART: |
387 | kernel_restart(NULL); | 395 | kernel_restart(NULL); |
@@ -397,20 +405,18 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, | |||
397 | 405 | ||
398 | case LINUX_REBOOT_CMD_HALT: | 406 | case LINUX_REBOOT_CMD_HALT: |
399 | kernel_halt(); | 407 | kernel_halt(); |
400 | unlock_kernel(); | ||
401 | do_exit(0); | 408 | do_exit(0); |
402 | panic("cannot halt"); | 409 | panic("cannot halt"); |
403 | 410 | ||
404 | case LINUX_REBOOT_CMD_POWER_OFF: | 411 | case LINUX_REBOOT_CMD_POWER_OFF: |
405 | kernel_power_off(); | 412 | kernel_power_off(); |
406 | unlock_kernel(); | ||
407 | do_exit(0); | 413 | do_exit(0); |
408 | break; | 414 | break; |
409 | 415 | ||
410 | case LINUX_REBOOT_CMD_RESTART2: | 416 | case LINUX_REBOOT_CMD_RESTART2: |
411 | if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { | 417 | if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) { |
412 | unlock_kernel(); | 418 | ret = -EFAULT; |
413 | return -EFAULT; | 419 | break; |
414 | } | 420 | } |
415 | buffer[sizeof(buffer) - 1] = '\0'; | 421 | buffer[sizeof(buffer) - 1] = '\0'; |
416 | 422 | ||
@@ -433,7 +439,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, | |||
433 | ret = -EINVAL; | 439 | ret = -EINVAL; |
434 | break; | 440 | break; |
435 | } | 441 | } |
436 | unlock_kernel(); | 442 | mutex_unlock(&reboot_mutex); |
437 | return ret; | 443 | return ret; |
438 | } | 444 | } |
439 | 445 | ||
@@ -486,10 +492,6 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
486 | return -ENOMEM; | 492 | return -ENOMEM; |
487 | old = current_cred(); | 493 | old = current_cred(); |
488 | 494 | ||
489 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | ||
490 | if (retval) | ||
491 | goto error; | ||
492 | |||
493 | retval = -EPERM; | 495 | retval = -EPERM; |
494 | if (rgid != (gid_t) -1) { | 496 | if (rgid != (gid_t) -1) { |
495 | if (old->gid == rgid || | 497 | if (old->gid == rgid || |
@@ -537,10 +539,6 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
537 | return -ENOMEM; | 539 | return -ENOMEM; |
538 | old = current_cred(); | 540 | old = current_cred(); |
539 | 541 | ||
540 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | ||
541 | if (retval) | ||
542 | goto error; | ||
543 | |||
544 | retval = -EPERM; | 542 | retval = -EPERM; |
545 | if (capable(CAP_SETGID)) | 543 | if (capable(CAP_SETGID)) |
546 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 544 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
@@ -567,13 +565,7 @@ static int set_user(struct cred *new) | |||
567 | if (!new_user) | 565 | if (!new_user) |
568 | return -EAGAIN; | 566 | return -EAGAIN; |
569 | 567 | ||
570 | if (!task_can_switch_user(new_user, current)) { | 568 | if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && |
571 | free_uid(new_user); | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | |||
575 | if (atomic_read(&new_user->processes) >= | ||
576 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && | ||
577 | new_user != INIT_USER) { | 569 | new_user != INIT_USER) { |
578 | free_uid(new_user); | 570 | free_uid(new_user); |
579 | return -EAGAIN; | 571 | return -EAGAIN; |
@@ -610,10 +602,6 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
610 | return -ENOMEM; | 602 | return -ENOMEM; |
611 | old = current_cred(); | 603 | old = current_cred(); |
612 | 604 | ||
613 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | ||
614 | if (retval) | ||
615 | goto error; | ||
616 | |||
617 | retval = -EPERM; | 605 | retval = -EPERM; |
618 | if (ruid != (uid_t) -1) { | 606 | if (ruid != (uid_t) -1) { |
619 | new->uid = ruid; | 607 | new->uid = ruid; |
@@ -675,10 +663,6 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
675 | return -ENOMEM; | 663 | return -ENOMEM; |
676 | old = current_cred(); | 664 | old = current_cred(); |
677 | 665 | ||
678 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | ||
679 | if (retval) | ||
680 | goto error; | ||
681 | |||
682 | retval = -EPERM; | 666 | retval = -EPERM; |
683 | if (capable(CAP_SETUID)) { | 667 | if (capable(CAP_SETUID)) { |
684 | new->suid = new->uid = uid; | 668 | new->suid = new->uid = uid; |
@@ -719,9 +703,6 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
719 | if (!new) | 703 | if (!new) |
720 | return -ENOMEM; | 704 | return -ENOMEM; |
721 | 705 | ||
722 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | ||
723 | if (retval) | ||
724 | goto error; | ||
725 | old = current_cred(); | 706 | old = current_cred(); |
726 | 707 | ||
727 | retval = -EPERM; | 708 | retval = -EPERM; |
@@ -788,10 +769,6 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
788 | return -ENOMEM; | 769 | return -ENOMEM; |
789 | old = current_cred(); | 770 | old = current_cred(); |
790 | 771 | ||
791 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | ||
792 | if (retval) | ||
793 | goto error; | ||
794 | |||
795 | retval = -EPERM; | 772 | retval = -EPERM; |
796 | if (!capable(CAP_SETGID)) { | 773 | if (!capable(CAP_SETGID)) { |
797 | if (rgid != (gid_t) -1 && rgid != old->gid && | 774 | if (rgid != (gid_t) -1 && rgid != old->gid && |
@@ -851,9 +828,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
851 | old = current_cred(); | 828 | old = current_cred(); |
852 | old_fsuid = old->fsuid; | 829 | old_fsuid = old->fsuid; |
853 | 830 | ||
854 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0) | ||
855 | goto error; | ||
856 | |||
857 | if (uid == old->uid || uid == old->euid || | 831 | if (uid == old->uid || uid == old->euid || |
858 | uid == old->suid || uid == old->fsuid || | 832 | uid == old->suid || uid == old->fsuid || |
859 | capable(CAP_SETUID)) { | 833 | capable(CAP_SETUID)) { |
@@ -864,7 +838,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
864 | } | 838 | } |
865 | } | 839 | } |
866 | 840 | ||
867 | error: | ||
868 | abort_creds(new); | 841 | abort_creds(new); |
869 | return old_fsuid; | 842 | return old_fsuid; |
870 | 843 | ||
@@ -888,9 +861,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
888 | old = current_cred(); | 861 | old = current_cred(); |
889 | old_fsgid = old->fsgid; | 862 | old_fsgid = old->fsgid; |
890 | 863 | ||
891 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | ||
892 | goto error; | ||
893 | |||
894 | if (gid == old->gid || gid == old->egid || | 864 | if (gid == old->gid || gid == old->egid || |
895 | gid == old->sgid || gid == old->fsgid || | 865 | gid == old->sgid || gid == old->fsgid || |
896 | capable(CAP_SETGID)) { | 866 | capable(CAP_SETGID)) { |
@@ -900,7 +870,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
900 | } | 870 | } |
901 | } | 871 | } |
902 | 872 | ||
903 | error: | ||
904 | abort_creds(new); | 873 | abort_creds(new); |
905 | return old_fsgid; | 874 | return old_fsgid; |
906 | 875 | ||
@@ -911,16 +880,15 @@ change_okay: | |||
911 | 880 | ||
912 | void do_sys_times(struct tms *tms) | 881 | void do_sys_times(struct tms *tms) |
913 | { | 882 | { |
914 | struct task_cputime cputime; | 883 | cputime_t tgutime, tgstime, cutime, cstime; |
915 | cputime_t cutime, cstime; | ||
916 | 884 | ||
917 | thread_group_cputime(current, &cputime); | ||
918 | spin_lock_irq(¤t->sighand->siglock); | 885 | spin_lock_irq(¤t->sighand->siglock); |
886 | thread_group_times(current, &tgutime, &tgstime); | ||
919 | cutime = current->signal->cutime; | 887 | cutime = current->signal->cutime; |
920 | cstime = current->signal->cstime; | 888 | cstime = current->signal->cstime; |
921 | spin_unlock_irq(¤t->sighand->siglock); | 889 | spin_unlock_irq(¤t->sighand->siglock); |
922 | tms->tms_utime = cputime_to_clock_t(cputime.utime); | 890 | tms->tms_utime = cputime_to_clock_t(tgutime); |
923 | tms->tms_stime = cputime_to_clock_t(cputime.stime); | 891 | tms->tms_stime = cputime_to_clock_t(tgstime); |
924 | tms->tms_cutime = cputime_to_clock_t(cutime); | 892 | tms->tms_cutime = cputime_to_clock_t(cutime); |
925 | tms->tms_cstime = cputime_to_clock_t(cstime); | 893 | tms->tms_cstime = cputime_to_clock_t(cstime); |
926 | } | 894 | } |
@@ -963,6 +931,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) | |||
963 | pgid = pid; | 931 | pgid = pid; |
964 | if (pgid < 0) | 932 | if (pgid < 0) |
965 | return -EINVAL; | 933 | return -EINVAL; |
934 | rcu_read_lock(); | ||
966 | 935 | ||
967 | /* From this point forward we keep holding onto the tasklist lock | 936 | /* From this point forward we keep holding onto the tasklist lock |
968 | * so that our parent does not change from under us. -DaveM | 937 | * so that our parent does not change from under us. -DaveM |
@@ -1016,6 +985,7 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) | |||
1016 | out: | 985 | out: |
1017 | /* All paths lead to here, thus we are safe. -DaveM */ | 986 | /* All paths lead to here, thus we are safe. -DaveM */ |
1018 | write_unlock_irq(&tasklist_lock); | 987 | write_unlock_irq(&tasklist_lock); |
988 | rcu_read_unlock(); | ||
1019 | return err; | 989 | return err; |
1020 | } | 990 | } |
1021 | 991 | ||
@@ -1110,11 +1080,24 @@ SYSCALL_DEFINE0(setsid) | |||
1110 | err = session; | 1080 | err = session; |
1111 | out: | 1081 | out: |
1112 | write_unlock_irq(&tasklist_lock); | 1082 | write_unlock_irq(&tasklist_lock); |
1083 | if (err > 0) { | ||
1084 | proc_sid_connector(group_leader); | ||
1085 | sched_autogroup_create_attach(group_leader); | ||
1086 | } | ||
1113 | return err; | 1087 | return err; |
1114 | } | 1088 | } |
1115 | 1089 | ||
1116 | DECLARE_RWSEM(uts_sem); | 1090 | DECLARE_RWSEM(uts_sem); |
1117 | 1091 | ||
1092 | #ifdef COMPAT_UTS_MACHINE | ||
1093 | #define override_architecture(name) \ | ||
1094 | (personality(current->personality) == PER_LINUX32 && \ | ||
1095 | copy_to_user(name->machine, COMPAT_UTS_MACHINE, \ | ||
1096 | sizeof(COMPAT_UTS_MACHINE))) | ||
1097 | #else | ||
1098 | #define override_architecture(name) 0 | ||
1099 | #endif | ||
1100 | |||
1118 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | 1101 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) |
1119 | { | 1102 | { |
1120 | int errno = 0; | 1103 | int errno = 0; |
@@ -1123,9 +1106,66 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | |||
1123 | if (copy_to_user(name, utsname(), sizeof *name)) | 1106 | if (copy_to_user(name, utsname(), sizeof *name)) |
1124 | errno = -EFAULT; | 1107 | errno = -EFAULT; |
1125 | up_read(&uts_sem); | 1108 | up_read(&uts_sem); |
1109 | |||
1110 | if (!errno && override_architecture(name)) | ||
1111 | errno = -EFAULT; | ||
1126 | return errno; | 1112 | return errno; |
1127 | } | 1113 | } |
1128 | 1114 | ||
1115 | #ifdef __ARCH_WANT_SYS_OLD_UNAME | ||
1116 | /* | ||
1117 | * Old cruft | ||
1118 | */ | ||
1119 | SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) | ||
1120 | { | ||
1121 | int error = 0; | ||
1122 | |||
1123 | if (!name) | ||
1124 | return -EFAULT; | ||
1125 | |||
1126 | down_read(&uts_sem); | ||
1127 | if (copy_to_user(name, utsname(), sizeof(*name))) | ||
1128 | error = -EFAULT; | ||
1129 | up_read(&uts_sem); | ||
1130 | |||
1131 | if (!error && override_architecture(name)) | ||
1132 | error = -EFAULT; | ||
1133 | return error; | ||
1134 | } | ||
1135 | |||
1136 | SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) | ||
1137 | { | ||
1138 | int error; | ||
1139 | |||
1140 | if (!name) | ||
1141 | return -EFAULT; | ||
1142 | if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) | ||
1143 | return -EFAULT; | ||
1144 | |||
1145 | down_read(&uts_sem); | ||
1146 | error = __copy_to_user(&name->sysname, &utsname()->sysname, | ||
1147 | __OLD_UTS_LEN); | ||
1148 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); | ||
1149 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, | ||
1150 | __OLD_UTS_LEN); | ||
1151 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); | ||
1152 | error |= __copy_to_user(&name->release, &utsname()->release, | ||
1153 | __OLD_UTS_LEN); | ||
1154 | error |= __put_user(0, name->release + __OLD_UTS_LEN); | ||
1155 | error |= __copy_to_user(&name->version, &utsname()->version, | ||
1156 | __OLD_UTS_LEN); | ||
1157 | error |= __put_user(0, name->version + __OLD_UTS_LEN); | ||
1158 | error |= __copy_to_user(&name->machine, &utsname()->machine, | ||
1159 | __OLD_UTS_LEN); | ||
1160 | error |= __put_user(0, name->machine + __OLD_UTS_LEN); | ||
1161 | up_read(&uts_sem); | ||
1162 | |||
1163 | if (!error && override_architecture(name)) | ||
1164 | error = -EFAULT; | ||
1165 | return error ? -EFAULT : 0; | ||
1166 | } | ||
1167 | #endif | ||
1168 | |||
1129 | SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | 1169 | SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) |
1130 | { | 1170 | { |
1131 | int errno; | 1171 | int errno; |
@@ -1200,15 +1240,14 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1200 | 1240 | ||
1201 | SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 1241 | SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) |
1202 | { | 1242 | { |
1203 | if (resource >= RLIM_NLIMITS) | 1243 | struct rlimit value; |
1204 | return -EINVAL; | 1244 | int ret; |
1205 | else { | 1245 | |
1206 | struct rlimit value; | 1246 | ret = do_prlimit(current, resource, NULL, &value); |
1207 | task_lock(current->group_leader); | 1247 | if (!ret) |
1208 | value = current->signal->rlim[resource]; | 1248 | ret = copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; |
1209 | task_unlock(current->group_leader); | 1249 | |
1210 | return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; | 1250 | return ret; |
1211 | } | ||
1212 | } | 1251 | } |
1213 | 1252 | ||
1214 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT | 1253 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT |
@@ -1236,44 +1275,89 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, | |||
1236 | 1275 | ||
1237 | #endif | 1276 | #endif |
1238 | 1277 | ||
1239 | SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 1278 | static inline bool rlim64_is_infinity(__u64 rlim64) |
1240 | { | 1279 | { |
1241 | struct rlimit new_rlim, *old_rlim; | 1280 | #if BITS_PER_LONG < 64 |
1242 | int retval; | 1281 | return rlim64 >= ULONG_MAX; |
1282 | #else | ||
1283 | return rlim64 == RLIM64_INFINITY; | ||
1284 | #endif | ||
1285 | } | ||
1286 | |||
1287 | static void rlim_to_rlim64(const struct rlimit *rlim, struct rlimit64 *rlim64) | ||
1288 | { | ||
1289 | if (rlim->rlim_cur == RLIM_INFINITY) | ||
1290 | rlim64->rlim_cur = RLIM64_INFINITY; | ||
1291 | else | ||
1292 | rlim64->rlim_cur = rlim->rlim_cur; | ||
1293 | if (rlim->rlim_max == RLIM_INFINITY) | ||
1294 | rlim64->rlim_max = RLIM64_INFINITY; | ||
1295 | else | ||
1296 | rlim64->rlim_max = rlim->rlim_max; | ||
1297 | } | ||
1298 | |||
1299 | static void rlim64_to_rlim(const struct rlimit64 *rlim64, struct rlimit *rlim) | ||
1300 | { | ||
1301 | if (rlim64_is_infinity(rlim64->rlim_cur)) | ||
1302 | rlim->rlim_cur = RLIM_INFINITY; | ||
1303 | else | ||
1304 | rlim->rlim_cur = (unsigned long)rlim64->rlim_cur; | ||
1305 | if (rlim64_is_infinity(rlim64->rlim_max)) | ||
1306 | rlim->rlim_max = RLIM_INFINITY; | ||
1307 | else | ||
1308 | rlim->rlim_max = (unsigned long)rlim64->rlim_max; | ||
1309 | } | ||
1310 | |||
1311 | /* make sure you are allowed to change @tsk limits before calling this */ | ||
1312 | int do_prlimit(struct task_struct *tsk, unsigned int resource, | ||
1313 | struct rlimit *new_rlim, struct rlimit *old_rlim) | ||
1314 | { | ||
1315 | struct rlimit *rlim; | ||
1316 | int retval = 0; | ||
1243 | 1317 | ||
1244 | if (resource >= RLIM_NLIMITS) | 1318 | if (resource >= RLIM_NLIMITS) |
1245 | return -EINVAL; | 1319 | return -EINVAL; |
1246 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | 1320 | if (new_rlim) { |
1247 | return -EFAULT; | 1321 | if (new_rlim->rlim_cur > new_rlim->rlim_max) |
1248 | if (new_rlim.rlim_cur > new_rlim.rlim_max) | 1322 | return -EINVAL; |
1249 | return -EINVAL; | 1323 | if (resource == RLIMIT_NOFILE && |
1250 | old_rlim = current->signal->rlim + resource; | 1324 | new_rlim->rlim_max > sysctl_nr_open) |
1251 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && | 1325 | return -EPERM; |
1252 | !capable(CAP_SYS_RESOURCE)) | ||
1253 | return -EPERM; | ||
1254 | if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) | ||
1255 | return -EPERM; | ||
1256 | |||
1257 | retval = security_task_setrlimit(resource, &new_rlim); | ||
1258 | if (retval) | ||
1259 | return retval; | ||
1260 | |||
1261 | if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) { | ||
1262 | /* | ||
1263 | * The caller is asking for an immediate RLIMIT_CPU | ||
1264 | * expiry. But we use the zero value to mean "it was | ||
1265 | * never set". So let's cheat and make it one second | ||
1266 | * instead | ||
1267 | */ | ||
1268 | new_rlim.rlim_cur = 1; | ||
1269 | } | 1326 | } |
1270 | 1327 | ||
1271 | task_lock(current->group_leader); | 1328 | /* protect tsk->signal and tsk->sighand from disappearing */ |
1272 | *old_rlim = new_rlim; | 1329 | read_lock(&tasklist_lock); |
1273 | task_unlock(current->group_leader); | 1330 | if (!tsk->sighand) { |
1274 | 1331 | retval = -ESRCH; | |
1275 | if (resource != RLIMIT_CPU) | ||
1276 | goto out; | 1332 | goto out; |
1333 | } | ||
1334 | |||
1335 | rlim = tsk->signal->rlim + resource; | ||
1336 | task_lock(tsk->group_leader); | ||
1337 | if (new_rlim) { | ||
1338 | if (new_rlim->rlim_max > rlim->rlim_max && | ||
1339 | !capable(CAP_SYS_RESOURCE)) | ||
1340 | retval = -EPERM; | ||
1341 | if (!retval) | ||
1342 | retval = security_task_setrlimit(tsk->group_leader, | ||
1343 | resource, new_rlim); | ||
1344 | if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { | ||
1345 | /* | ||
1346 | * The caller is asking for an immediate RLIMIT_CPU | ||
1347 | * expiry. But we use the zero value to mean "it was | ||
1348 | * never set". So let's cheat and make it one second | ||
1349 | * instead | ||
1350 | */ | ||
1351 | new_rlim->rlim_cur = 1; | ||
1352 | } | ||
1353 | } | ||
1354 | if (!retval) { | ||
1355 | if (old_rlim) | ||
1356 | *old_rlim = *rlim; | ||
1357 | if (new_rlim) | ||
1358 | *rlim = *new_rlim; | ||
1359 | } | ||
1360 | task_unlock(tsk->group_leader); | ||
1277 | 1361 | ||
1278 | /* | 1362 | /* |
1279 | * RLIMIT_CPU handling. Note that the kernel fails to return an error | 1363 | * RLIMIT_CPU handling. Note that the kernel fails to return an error |
@@ -1281,14 +1365,84 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | |||
1281 | * very long-standing error, and fixing it now risks breakage of | 1365 | * very long-standing error, and fixing it now risks breakage of |
1282 | * applications, so we live with it | 1366 | * applications, so we live with it |
1283 | */ | 1367 | */ |
1284 | if (new_rlim.rlim_cur == RLIM_INFINITY) | 1368 | if (!retval && new_rlim && resource == RLIMIT_CPU && |
1285 | goto out; | 1369 | new_rlim->rlim_cur != RLIM_INFINITY) |
1286 | 1370 | update_rlimit_cpu(tsk, new_rlim->rlim_cur); | |
1287 | update_rlimit_cpu(new_rlim.rlim_cur); | ||
1288 | out: | 1371 | out: |
1372 | read_unlock(&tasklist_lock); | ||
1373 | return retval; | ||
1374 | } | ||
1375 | |||
1376 | /* rcu lock must be held */ | ||
1377 | static int check_prlimit_permission(struct task_struct *task) | ||
1378 | { | ||
1379 | const struct cred *cred = current_cred(), *tcred; | ||
1380 | |||
1381 | tcred = __task_cred(task); | ||
1382 | if ((cred->uid != tcred->euid || | ||
1383 | cred->uid != tcred->suid || | ||
1384 | cred->uid != tcred->uid || | ||
1385 | cred->gid != tcred->egid || | ||
1386 | cred->gid != tcred->sgid || | ||
1387 | cred->gid != tcred->gid) && | ||
1388 | !capable(CAP_SYS_RESOURCE)) { | ||
1389 | return -EPERM; | ||
1390 | } | ||
1391 | |||
1289 | return 0; | 1392 | return 0; |
1290 | } | 1393 | } |
1291 | 1394 | ||
1395 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | ||
1396 | const struct rlimit64 __user *, new_rlim, | ||
1397 | struct rlimit64 __user *, old_rlim) | ||
1398 | { | ||
1399 | struct rlimit64 old64, new64; | ||
1400 | struct rlimit old, new; | ||
1401 | struct task_struct *tsk; | ||
1402 | int ret; | ||
1403 | |||
1404 | if (new_rlim) { | ||
1405 | if (copy_from_user(&new64, new_rlim, sizeof(new64))) | ||
1406 | return -EFAULT; | ||
1407 | rlim64_to_rlim(&new64, &new); | ||
1408 | } | ||
1409 | |||
1410 | rcu_read_lock(); | ||
1411 | tsk = pid ? find_task_by_vpid(pid) : current; | ||
1412 | if (!tsk) { | ||
1413 | rcu_read_unlock(); | ||
1414 | return -ESRCH; | ||
1415 | } | ||
1416 | ret = check_prlimit_permission(tsk); | ||
1417 | if (ret) { | ||
1418 | rcu_read_unlock(); | ||
1419 | return ret; | ||
1420 | } | ||
1421 | get_task_struct(tsk); | ||
1422 | rcu_read_unlock(); | ||
1423 | |||
1424 | ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL, | ||
1425 | old_rlim ? &old : NULL); | ||
1426 | |||
1427 | if (!ret && old_rlim) { | ||
1428 | rlim_to_rlim64(&old, &old64); | ||
1429 | if (copy_to_user(old_rlim, &old64, sizeof(old64))) | ||
1430 | ret = -EFAULT; | ||
1431 | } | ||
1432 | |||
1433 | put_task_struct(tsk); | ||
1434 | return ret; | ||
1435 | } | ||
1436 | |||
1437 | SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | ||
1438 | { | ||
1439 | struct rlimit new_rlim; | ||
1440 | |||
1441 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | ||
1442 | return -EFAULT; | ||
1443 | return do_prlimit(current, resource, &new_rlim, NULL); | ||
1444 | } | ||
1445 | |||
1292 | /* | 1446 | /* |
1293 | * It would make sense to put struct rusage in the task_struct, | 1447 | * It would make sense to put struct rusage in the task_struct, |
1294 | * except that would make the task_struct be *really big*. After | 1448 | * except that would make the task_struct be *really big*. After |
@@ -1336,16 +1490,16 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1336 | { | 1490 | { |
1337 | struct task_struct *t; | 1491 | struct task_struct *t; |
1338 | unsigned long flags; | 1492 | unsigned long flags; |
1339 | cputime_t utime, stime; | 1493 | cputime_t tgutime, tgstime, utime, stime; |
1340 | struct task_cputime cputime; | 1494 | unsigned long maxrss = 0; |
1341 | 1495 | ||
1342 | memset((char *) r, 0, sizeof *r); | 1496 | memset((char *) r, 0, sizeof *r); |
1343 | utime = stime = cputime_zero; | 1497 | utime = stime = cputime_zero; |
1344 | 1498 | ||
1345 | if (who == RUSAGE_THREAD) { | 1499 | if (who == RUSAGE_THREAD) { |
1346 | utime = task_utime(current); | 1500 | task_times(current, &utime, &stime); |
1347 | stime = task_stime(current); | ||
1348 | accumulate_thread_rusage(p, r); | 1501 | accumulate_thread_rusage(p, r); |
1502 | maxrss = p->signal->maxrss; | ||
1349 | goto out; | 1503 | goto out; |
1350 | } | 1504 | } |
1351 | 1505 | ||
@@ -1363,20 +1517,23 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1363 | r->ru_majflt = p->signal->cmaj_flt; | 1517 | r->ru_majflt = p->signal->cmaj_flt; |
1364 | r->ru_inblock = p->signal->cinblock; | 1518 | r->ru_inblock = p->signal->cinblock; |
1365 | r->ru_oublock = p->signal->coublock; | 1519 | r->ru_oublock = p->signal->coublock; |
1520 | maxrss = p->signal->cmaxrss; | ||
1366 | 1521 | ||
1367 | if (who == RUSAGE_CHILDREN) | 1522 | if (who == RUSAGE_CHILDREN) |
1368 | break; | 1523 | break; |
1369 | 1524 | ||
1370 | case RUSAGE_SELF: | 1525 | case RUSAGE_SELF: |
1371 | thread_group_cputime(p, &cputime); | 1526 | thread_group_times(p, &tgutime, &tgstime); |
1372 | utime = cputime_add(utime, cputime.utime); | 1527 | utime = cputime_add(utime, tgutime); |
1373 | stime = cputime_add(stime, cputime.stime); | 1528 | stime = cputime_add(stime, tgstime); |
1374 | r->ru_nvcsw += p->signal->nvcsw; | 1529 | r->ru_nvcsw += p->signal->nvcsw; |
1375 | r->ru_nivcsw += p->signal->nivcsw; | 1530 | r->ru_nivcsw += p->signal->nivcsw; |
1376 | r->ru_minflt += p->signal->min_flt; | 1531 | r->ru_minflt += p->signal->min_flt; |
1377 | r->ru_majflt += p->signal->maj_flt; | 1532 | r->ru_majflt += p->signal->maj_flt; |
1378 | r->ru_inblock += p->signal->inblock; | 1533 | r->ru_inblock += p->signal->inblock; |
1379 | r->ru_oublock += p->signal->oublock; | 1534 | r->ru_oublock += p->signal->oublock; |
1535 | if (maxrss < p->signal->maxrss) | ||
1536 | maxrss = p->signal->maxrss; | ||
1380 | t = p; | 1537 | t = p; |
1381 | do { | 1538 | do { |
1382 | accumulate_thread_rusage(t, r); | 1539 | accumulate_thread_rusage(t, r); |
@@ -1392,6 +1549,15 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1392 | out: | 1549 | out: |
1393 | cputime_to_timeval(utime, &r->ru_utime); | 1550 | cputime_to_timeval(utime, &r->ru_utime); |
1394 | cputime_to_timeval(stime, &r->ru_stime); | 1551 | cputime_to_timeval(stime, &r->ru_stime); |
1552 | |||
1553 | if (who != RUSAGE_CHILDREN) { | ||
1554 | struct mm_struct *mm = get_task_mm(p); | ||
1555 | if (mm) { | ||
1556 | setmax_mm_hiwater_rss(&maxrss, mm); | ||
1557 | mmput(mm); | ||
1558 | } | ||
1559 | } | ||
1560 | r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */ | ||
1395 | } | 1561 | } |
1396 | 1562 | ||
1397 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) | 1563 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) |
@@ -1511,11 +1677,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1511 | case PR_SET_TSC: | 1677 | case PR_SET_TSC: |
1512 | error = SET_TSC_CTL(arg2); | 1678 | error = SET_TSC_CTL(arg2); |
1513 | break; | 1679 | break; |
1514 | case PR_TASK_PERF_COUNTERS_DISABLE: | 1680 | case PR_TASK_PERF_EVENTS_DISABLE: |
1515 | error = perf_counter_task_disable(); | 1681 | error = perf_event_task_disable(); |
1516 | break; | 1682 | break; |
1517 | case PR_TASK_PERF_COUNTERS_ENABLE: | 1683 | case PR_TASK_PERF_EVENTS_ENABLE: |
1518 | error = perf_counter_task_enable(); | 1684 | error = perf_event_task_enable(); |
1519 | break; | 1685 | break; |
1520 | case PR_GET_TIMERSLACK: | 1686 | case PR_GET_TIMERSLACK: |
1521 | error = current->timer_slack_ns; | 1687 | error = current->timer_slack_ns; |
@@ -1528,6 +1694,41 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1528 | current->timer_slack_ns = arg2; | 1694 | current->timer_slack_ns = arg2; |
1529 | error = 0; | 1695 | error = 0; |
1530 | break; | 1696 | break; |
1697 | case PR_MCE_KILL: | ||
1698 | if (arg4 | arg5) | ||
1699 | return -EINVAL; | ||
1700 | switch (arg2) { | ||
1701 | case PR_MCE_KILL_CLEAR: | ||
1702 | if (arg3 != 0) | ||
1703 | return -EINVAL; | ||
1704 | current->flags &= ~PF_MCE_PROCESS; | ||
1705 | break; | ||
1706 | case PR_MCE_KILL_SET: | ||
1707 | current->flags |= PF_MCE_PROCESS; | ||
1708 | if (arg3 == PR_MCE_KILL_EARLY) | ||
1709 | current->flags |= PF_MCE_EARLY; | ||
1710 | else if (arg3 == PR_MCE_KILL_LATE) | ||
1711 | current->flags &= ~PF_MCE_EARLY; | ||
1712 | else if (arg3 == PR_MCE_KILL_DEFAULT) | ||
1713 | current->flags &= | ||
1714 | ~(PF_MCE_EARLY|PF_MCE_PROCESS); | ||
1715 | else | ||
1716 | return -EINVAL; | ||
1717 | break; | ||
1718 | default: | ||
1719 | return -EINVAL; | ||
1720 | } | ||
1721 | error = 0; | ||
1722 | break; | ||
1723 | case PR_MCE_KILL_GET: | ||
1724 | if (arg2 | arg3 | arg4 | arg5) | ||
1725 | return -EINVAL; | ||
1726 | if (current->flags & PF_MCE_PROCESS) | ||
1727 | error = (current->flags & PF_MCE_EARLY) ? | ||
1728 | PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE; | ||
1729 | else | ||
1730 | error = PR_MCE_KILL_DEFAULT; | ||
1731 | break; | ||
1531 | default: | 1732 | default: |
1532 | error = -EINVAL; | 1733 | error = -EINVAL; |
1533 | break; | 1734 | break; |
@@ -1549,9 +1750,9 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, | |||
1549 | 1750 | ||
1550 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; | 1751 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; |
1551 | 1752 | ||
1552 | static void argv_cleanup(char **argv, char **envp) | 1753 | static void argv_cleanup(struct subprocess_info *info) |
1553 | { | 1754 | { |
1554 | argv_free(argv); | 1755 | argv_free(info->argv); |
1555 | } | 1756 | } |
1556 | 1757 | ||
1557 | /** | 1758 | /** |
@@ -1585,7 +1786,7 @@ int orderly_poweroff(bool force) | |||
1585 | goto out; | 1786 | goto out; |
1586 | } | 1787 | } |
1587 | 1788 | ||
1588 | call_usermodehelper_setcleanup(info, argv_cleanup); | 1789 | call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL); |
1589 | 1790 | ||
1590 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); | 1791 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); |
1591 | 1792 | ||