diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 103 |
1 files changed, 55 insertions, 48 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index bce933ebb29f..0929c698affc 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/kexec.h> | 20 | #include <linux/kexec.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/workqueue.h> |
22 | #include <linux/capability.h> | ||
22 | #include <linux/device.h> | 23 | #include <linux/device.h> |
23 | #include <linux/key.h> | 24 | #include <linux/key.h> |
24 | #include <linux/times.h> | 25 | #include <linux/times.h> |
@@ -32,6 +33,7 @@ | |||
32 | 33 | ||
33 | #include <linux/compat.h> | 34 | #include <linux/compat.h> |
34 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
36 | #include <linux/kprobes.h> | ||
35 | 37 | ||
36 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
37 | #include <asm/io.h> | 39 | #include <asm/io.h> |
@@ -168,7 +170,7 @@ EXPORT_SYMBOL(notifier_chain_unregister); | |||
168 | * of the last notifier function called. | 170 | * of the last notifier function called. |
169 | */ | 171 | */ |
170 | 172 | ||
171 | int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) | 173 | int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) |
172 | { | 174 | { |
173 | int ret=NOTIFY_DONE; | 175 | int ret=NOTIFY_DONE; |
174 | struct notifier_block *nb = *n; | 176 | struct notifier_block *nb = *n; |
@@ -222,6 +224,18 @@ int unregister_reboot_notifier(struct notifier_block * nb) | |||
222 | 224 | ||
223 | EXPORT_SYMBOL(unregister_reboot_notifier); | 225 | EXPORT_SYMBOL(unregister_reboot_notifier); |
224 | 226 | ||
227 | #ifndef CONFIG_SECURITY | ||
228 | int capable(int cap) | ||
229 | { | ||
230 | if (cap_raised(current->cap_effective, cap)) { | ||
231 | current->flags |= PF_SUPERPRIV; | ||
232 | return 1; | ||
233 | } | ||
234 | return 0; | ||
235 | } | ||
236 | EXPORT_SYMBOL(capable); | ||
237 | #endif | ||
238 | |||
225 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 239 | static int set_one_prio(struct task_struct *p, int niceval, int error) |
226 | { | 240 | { |
227 | int no_nice; | 241 | int no_nice; |
@@ -426,23 +440,25 @@ void kernel_kexec(void) | |||
426 | } | 440 | } |
427 | EXPORT_SYMBOL_GPL(kernel_kexec); | 441 | EXPORT_SYMBOL_GPL(kernel_kexec); |
428 | 442 | ||
443 | void kernel_shutdown_prepare(enum system_states state) | ||
444 | { | ||
445 | notifier_call_chain(&reboot_notifier_list, | ||
446 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); | ||
447 | system_state = state; | ||
448 | device_shutdown(); | ||
449 | } | ||
429 | /** | 450 | /** |
430 | * kernel_halt - halt the system | 451 | * kernel_halt - halt the system |
431 | * | 452 | * |
432 | * Shutdown everything and perform a clean system halt. | 453 | * Shutdown everything and perform a clean system halt. |
433 | */ | 454 | */ |
434 | void kernel_halt_prepare(void) | ||
435 | { | ||
436 | notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); | ||
437 | system_state = SYSTEM_HALT; | ||
438 | device_shutdown(); | ||
439 | } | ||
440 | void kernel_halt(void) | 455 | void kernel_halt(void) |
441 | { | 456 | { |
442 | kernel_halt_prepare(); | 457 | kernel_shutdown_prepare(SYSTEM_HALT); |
443 | printk(KERN_EMERG "System halted.\n"); | 458 | printk(KERN_EMERG "System halted.\n"); |
444 | machine_halt(); | 459 | machine_halt(); |
445 | } | 460 | } |
461 | |||
446 | EXPORT_SYMBOL_GPL(kernel_halt); | 462 | EXPORT_SYMBOL_GPL(kernel_halt); |
447 | 463 | ||
448 | /** | 464 | /** |
@@ -450,20 +466,13 @@ EXPORT_SYMBOL_GPL(kernel_halt); | |||
450 | * | 466 | * |
451 | * Shutdown everything and perform a clean system power_off. | 467 | * Shutdown everything and perform a clean system power_off. |
452 | */ | 468 | */ |
453 | void kernel_power_off_prepare(void) | ||
454 | { | ||
455 | notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); | ||
456 | system_state = SYSTEM_POWER_OFF; | ||
457 | device_shutdown(); | ||
458 | } | ||
459 | void kernel_power_off(void) | 469 | void kernel_power_off(void) |
460 | { | 470 | { |
461 | kernel_power_off_prepare(); | 471 | kernel_shutdown_prepare(SYSTEM_POWER_OFF); |
462 | printk(KERN_EMERG "Power down.\n"); | 472 | printk(KERN_EMERG "Power down.\n"); |
463 | machine_power_off(); | 473 | machine_power_off(); |
464 | } | 474 | } |
465 | EXPORT_SYMBOL_GPL(kernel_power_off); | 475 | EXPORT_SYMBOL_GPL(kernel_power_off); |
466 | |||
467 | /* | 476 | /* |
468 | * Reboot system call: for obvious reasons only root may call it, | 477 | * Reboot system call: for obvious reasons only root may call it, |
469 | * and even root needs to set up some magic numbers in the registers | 478 | * and even root needs to set up some magic numbers in the registers |
@@ -488,6 +497,12 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user | |||
488 | magic2 != LINUX_REBOOT_MAGIC2C)) | 497 | magic2 != LINUX_REBOOT_MAGIC2C)) |
489 | return -EINVAL; | 498 | return -EINVAL; |
490 | 499 | ||
500 | /* Instead of trying to make the power_off code look like | ||
501 | * halt when pm_power_off is not set do it the easy way. | ||
502 | */ | ||
503 | if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) | ||
504 | cmd = LINUX_REBOOT_CMD_HALT; | ||
505 | |||
491 | lock_kernel(); | 506 | lock_kernel(); |
492 | switch (cmd) { | 507 | switch (cmd) { |
493 | case LINUX_REBOOT_CMD_RESTART: | 508 | case LINUX_REBOOT_CMD_RESTART: |
@@ -1083,10 +1098,11 @@ asmlinkage long sys_times(struct tms __user * tbuf) | |||
1083 | asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) | 1098 | asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) |
1084 | { | 1099 | { |
1085 | struct task_struct *p; | 1100 | struct task_struct *p; |
1101 | struct task_struct *group_leader = current->group_leader; | ||
1086 | int err = -EINVAL; | 1102 | int err = -EINVAL; |
1087 | 1103 | ||
1088 | if (!pid) | 1104 | if (!pid) |
1089 | pid = current->pid; | 1105 | pid = group_leader->pid; |
1090 | if (!pgid) | 1106 | if (!pgid) |
1091 | pgid = pid; | 1107 | pgid = pid; |
1092 | if (pgid < 0) | 1108 | if (pgid < 0) |
@@ -1106,16 +1122,16 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) | |||
1106 | if (!thread_group_leader(p)) | 1122 | if (!thread_group_leader(p)) |
1107 | goto out; | 1123 | goto out; |
1108 | 1124 | ||
1109 | if (p->parent == current || p->real_parent == current) { | 1125 | if (p->real_parent == group_leader) { |
1110 | err = -EPERM; | 1126 | err = -EPERM; |
1111 | if (p->signal->session != current->signal->session) | 1127 | if (p->signal->session != group_leader->signal->session) |
1112 | goto out; | 1128 | goto out; |
1113 | err = -EACCES; | 1129 | err = -EACCES; |
1114 | if (p->did_exec) | 1130 | if (p->did_exec) |
1115 | goto out; | 1131 | goto out; |
1116 | } else { | 1132 | } else { |
1117 | err = -ESRCH; | 1133 | err = -ESRCH; |
1118 | if (p != current) | 1134 | if (p != group_leader) |
1119 | goto out; | 1135 | goto out; |
1120 | } | 1136 | } |
1121 | 1137 | ||
@@ -1127,7 +1143,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) | |||
1127 | struct task_struct *p; | 1143 | struct task_struct *p; |
1128 | 1144 | ||
1129 | do_each_task_pid(pgid, PIDTYPE_PGID, p) { | 1145 | do_each_task_pid(pgid, PIDTYPE_PGID, p) { |
1130 | if (p->signal->session == current->signal->session) | 1146 | if (p->signal->session == group_leader->signal->session) |
1131 | goto ok_pgid; | 1147 | goto ok_pgid; |
1132 | } while_each_task_pid(pgid, PIDTYPE_PGID, p); | 1148 | } while_each_task_pid(pgid, PIDTYPE_PGID, p); |
1133 | goto out; | 1149 | goto out; |
@@ -1207,24 +1223,22 @@ asmlinkage long sys_getsid(pid_t pid) | |||
1207 | 1223 | ||
1208 | asmlinkage long sys_setsid(void) | 1224 | asmlinkage long sys_setsid(void) |
1209 | { | 1225 | { |
1226 | struct task_struct *group_leader = current->group_leader; | ||
1210 | struct pid *pid; | 1227 | struct pid *pid; |
1211 | int err = -EPERM; | 1228 | int err = -EPERM; |
1212 | 1229 | ||
1213 | if (!thread_group_leader(current)) | ||
1214 | return -EINVAL; | ||
1215 | |||
1216 | down(&tty_sem); | 1230 | down(&tty_sem); |
1217 | write_lock_irq(&tasklist_lock); | 1231 | write_lock_irq(&tasklist_lock); |
1218 | 1232 | ||
1219 | pid = find_pid(PIDTYPE_PGID, current->pid); | 1233 | pid = find_pid(PIDTYPE_PGID, group_leader->pid); |
1220 | if (pid) | 1234 | if (pid) |
1221 | goto out; | 1235 | goto out; |
1222 | 1236 | ||
1223 | current->signal->leader = 1; | 1237 | group_leader->signal->leader = 1; |
1224 | __set_special_pids(current->pid, current->pid); | 1238 | __set_special_pids(group_leader->pid, group_leader->pid); |
1225 | current->signal->tty = NULL; | 1239 | group_leader->signal->tty = NULL; |
1226 | current->signal->tty_old_pgrp = 0; | 1240 | group_leader->signal->tty_old_pgrp = 0; |
1227 | err = process_group(current); | 1241 | err = process_group(group_leader); |
1228 | out: | 1242 | out: |
1229 | write_unlock_irq(&tasklist_lock); | 1243 | write_unlock_irq(&tasklist_lock); |
1230 | up(&tty_sem); | 1244 | up(&tty_sem); |
@@ -1686,7 +1700,10 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1686 | if (unlikely(!p->signal)) | 1700 | if (unlikely(!p->signal)) |
1687 | return; | 1701 | return; |
1688 | 1702 | ||
1703 | utime = stime = cputime_zero; | ||
1704 | |||
1689 | switch (who) { | 1705 | switch (who) { |
1706 | case RUSAGE_BOTH: | ||
1690 | case RUSAGE_CHILDREN: | 1707 | case RUSAGE_CHILDREN: |
1691 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1708 | spin_lock_irqsave(&p->sighand->siglock, flags); |
1692 | utime = p->signal->cutime; | 1709 | utime = p->signal->cutime; |
@@ -1696,22 +1713,11 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1696 | r->ru_minflt = p->signal->cmin_flt; | 1713 | r->ru_minflt = p->signal->cmin_flt; |
1697 | r->ru_majflt = p->signal->cmaj_flt; | 1714 | r->ru_majflt = p->signal->cmaj_flt; |
1698 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 1715 | spin_unlock_irqrestore(&p->sighand->siglock, flags); |
1699 | cputime_to_timeval(utime, &r->ru_utime); | 1716 | |
1700 | cputime_to_timeval(stime, &r->ru_stime); | 1717 | if (who == RUSAGE_CHILDREN) |
1701 | break; | 1718 | break; |
1719 | |||
1702 | case RUSAGE_SELF: | 1720 | case RUSAGE_SELF: |
1703 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
1704 | utime = stime = cputime_zero; | ||
1705 | goto sum_group; | ||
1706 | case RUSAGE_BOTH: | ||
1707 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
1708 | utime = p->signal->cutime; | ||
1709 | stime = p->signal->cstime; | ||
1710 | r->ru_nvcsw = p->signal->cnvcsw; | ||
1711 | r->ru_nivcsw = p->signal->cnivcsw; | ||
1712 | r->ru_minflt = p->signal->cmin_flt; | ||
1713 | r->ru_majflt = p->signal->cmaj_flt; | ||
1714 | sum_group: | ||
1715 | utime = cputime_add(utime, p->signal->utime); | 1721 | utime = cputime_add(utime, p->signal->utime); |
1716 | stime = cputime_add(stime, p->signal->stime); | 1722 | stime = cputime_add(stime, p->signal->stime); |
1717 | r->ru_nvcsw += p->signal->nvcsw; | 1723 | r->ru_nvcsw += p->signal->nvcsw; |
@@ -1728,13 +1734,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1728 | r->ru_majflt += t->maj_flt; | 1734 | r->ru_majflt += t->maj_flt; |
1729 | t = next_thread(t); | 1735 | t = next_thread(t); |
1730 | } while (t != p); | 1736 | } while (t != p); |
1731 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
1732 | cputime_to_timeval(utime, &r->ru_utime); | ||
1733 | cputime_to_timeval(stime, &r->ru_stime); | ||
1734 | break; | 1737 | break; |
1738 | |||
1735 | default: | 1739 | default: |
1736 | BUG(); | 1740 | BUG(); |
1737 | } | 1741 | } |
1742 | |||
1743 | cputime_to_timeval(utime, &r->ru_utime); | ||
1744 | cputime_to_timeval(stime, &r->ru_stime); | ||
1738 | } | 1745 | } |
1739 | 1746 | ||
1740 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) | 1747 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) |