diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 123 |
1 files changed, 93 insertions, 30 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index ce17760d9c51..6d1a7e0f9d5b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -8,7 +8,6 @@ | |||
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> |
@@ -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 | ||
@@ -567,13 +573,7 @@ static int set_user(struct cred *new) | |||
567 | if (!new_user) | 573 | if (!new_user) |
568 | return -EAGAIN; | 574 | return -EAGAIN; |
569 | 575 | ||
570 | if (!task_can_switch_user(new_user, current)) { | 576 | 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) { | 577 | new_user != INIT_USER) { |
578 | free_uid(new_user); | 578 | free_uid(new_user); |
579 | return -EAGAIN; | 579 | return -EAGAIN; |
@@ -911,16 +911,15 @@ change_okay: | |||
911 | 911 | ||
912 | void do_sys_times(struct tms *tms) | 912 | void do_sys_times(struct tms *tms) |
913 | { | 913 | { |
914 | struct task_cputime cputime; | 914 | cputime_t tgutime, tgstime, cutime, cstime; |
915 | cputime_t cutime, cstime; | ||
916 | 915 | ||
917 | thread_group_cputime(current, &cputime); | ||
918 | spin_lock_irq(¤t->sighand->siglock); | 916 | spin_lock_irq(¤t->sighand->siglock); |
917 | thread_group_times(current, &tgutime, &tgstime); | ||
919 | cutime = current->signal->cutime; | 918 | cutime = current->signal->cutime; |
920 | cstime = current->signal->cstime; | 919 | cstime = current->signal->cstime; |
921 | spin_unlock_irq(¤t->sighand->siglock); | 920 | spin_unlock_irq(¤t->sighand->siglock); |
922 | tms->tms_utime = cputime_to_clock_t(cputime.utime); | 921 | tms->tms_utime = cputime_to_clock_t(tgutime); |
923 | tms->tms_stime = cputime_to_clock_t(cputime.stime); | 922 | tms->tms_stime = cputime_to_clock_t(tgstime); |
924 | tms->tms_cutime = cputime_to_clock_t(cutime); | 923 | tms->tms_cutime = cputime_to_clock_t(cutime); |
925 | tms->tms_cstime = cputime_to_clock_t(cstime); | 924 | tms->tms_cstime = cputime_to_clock_t(cstime); |
926 | } | 925 | } |
@@ -1117,6 +1116,15 @@ out: | |||
1117 | 1116 | ||
1118 | DECLARE_RWSEM(uts_sem); | 1117 | DECLARE_RWSEM(uts_sem); |
1119 | 1118 | ||
1119 | #ifdef COMPAT_UTS_MACHINE | ||
1120 | #define override_architecture(name) \ | ||
1121 | (current->personality == PER_LINUX32 && \ | ||
1122 | copy_to_user(name->machine, COMPAT_UTS_MACHINE, \ | ||
1123 | sizeof(COMPAT_UTS_MACHINE))) | ||
1124 | #else | ||
1125 | #define override_architecture(name) 0 | ||
1126 | #endif | ||
1127 | |||
1120 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | 1128 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) |
1121 | { | 1129 | { |
1122 | int errno = 0; | 1130 | int errno = 0; |
@@ -1125,9 +1133,66 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | |||
1125 | if (copy_to_user(name, utsname(), sizeof *name)) | 1133 | if (copy_to_user(name, utsname(), sizeof *name)) |
1126 | errno = -EFAULT; | 1134 | errno = -EFAULT; |
1127 | up_read(&uts_sem); | 1135 | up_read(&uts_sem); |
1136 | |||
1137 | if (!errno && override_architecture(name)) | ||
1138 | errno = -EFAULT; | ||
1128 | return errno; | 1139 | return errno; |
1129 | } | 1140 | } |
1130 | 1141 | ||
1142 | #ifdef __ARCH_WANT_SYS_OLD_UNAME | ||
1143 | /* | ||
1144 | * Old cruft | ||
1145 | */ | ||
1146 | SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) | ||
1147 | { | ||
1148 | int error = 0; | ||
1149 | |||
1150 | if (!name) | ||
1151 | return -EFAULT; | ||
1152 | |||
1153 | down_read(&uts_sem); | ||
1154 | if (copy_to_user(name, utsname(), sizeof(*name))) | ||
1155 | error = -EFAULT; | ||
1156 | up_read(&uts_sem); | ||
1157 | |||
1158 | if (!error && override_architecture(name)) | ||
1159 | error = -EFAULT; | ||
1160 | return error; | ||
1161 | } | ||
1162 | |||
1163 | SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) | ||
1164 | { | ||
1165 | int error; | ||
1166 | |||
1167 | if (!name) | ||
1168 | return -EFAULT; | ||
1169 | if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) | ||
1170 | return -EFAULT; | ||
1171 | |||
1172 | down_read(&uts_sem); | ||
1173 | error = __copy_to_user(&name->sysname, &utsname()->sysname, | ||
1174 | __OLD_UTS_LEN); | ||
1175 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); | ||
1176 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, | ||
1177 | __OLD_UTS_LEN); | ||
1178 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); | ||
1179 | error |= __copy_to_user(&name->release, &utsname()->release, | ||
1180 | __OLD_UTS_LEN); | ||
1181 | error |= __put_user(0, name->release + __OLD_UTS_LEN); | ||
1182 | error |= __copy_to_user(&name->version, &utsname()->version, | ||
1183 | __OLD_UTS_LEN); | ||
1184 | error |= __put_user(0, name->version + __OLD_UTS_LEN); | ||
1185 | error |= __copy_to_user(&name->machine, &utsname()->machine, | ||
1186 | __OLD_UTS_LEN); | ||
1187 | error |= __put_user(0, name->machine + __OLD_UTS_LEN); | ||
1188 | up_read(&uts_sem); | ||
1189 | |||
1190 | if (!error && override_architecture(name)) | ||
1191 | error = -EFAULT; | ||
1192 | return error ? -EFAULT : 0; | ||
1193 | } | ||
1194 | #endif | ||
1195 | |||
1131 | SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | 1196 | SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) |
1132 | { | 1197 | { |
1133 | int errno; | 1198 | int errno; |
@@ -1338,16 +1403,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1338 | { | 1403 | { |
1339 | struct task_struct *t; | 1404 | struct task_struct *t; |
1340 | unsigned long flags; | 1405 | unsigned long flags; |
1341 | cputime_t utime, stime; | 1406 | cputime_t tgutime, tgstime, utime, stime; |
1342 | struct task_cputime cputime; | ||
1343 | unsigned long maxrss = 0; | 1407 | unsigned long maxrss = 0; |
1344 | 1408 | ||
1345 | memset((char *) r, 0, sizeof *r); | 1409 | memset((char *) r, 0, sizeof *r); |
1346 | utime = stime = cputime_zero; | 1410 | utime = stime = cputime_zero; |
1347 | 1411 | ||
1348 | if (who == RUSAGE_THREAD) { | 1412 | if (who == RUSAGE_THREAD) { |
1349 | utime = task_utime(current); | 1413 | task_times(current, &utime, &stime); |
1350 | stime = task_stime(current); | ||
1351 | accumulate_thread_rusage(p, r); | 1414 | accumulate_thread_rusage(p, r); |
1352 | maxrss = p->signal->maxrss; | 1415 | maxrss = p->signal->maxrss; |
1353 | goto out; | 1416 | goto out; |
@@ -1373,9 +1436,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1373 | break; | 1436 | break; |
1374 | 1437 | ||
1375 | case RUSAGE_SELF: | 1438 | case RUSAGE_SELF: |
1376 | thread_group_cputime(p, &cputime); | 1439 | thread_group_times(p, &tgutime, &tgstime); |
1377 | utime = cputime_add(utime, cputime.utime); | 1440 | utime = cputime_add(utime, tgutime); |
1378 | stime = cputime_add(stime, cputime.stime); | 1441 | stime = cputime_add(stime, tgstime); |
1379 | r->ru_nvcsw += p->signal->nvcsw; | 1442 | r->ru_nvcsw += p->signal->nvcsw; |
1380 | r->ru_nivcsw += p->signal->nivcsw; | 1443 | r->ru_nivcsw += p->signal->nivcsw; |
1381 | r->ru_minflt += p->signal->min_flt; | 1444 | r->ru_minflt += p->signal->min_flt; |