diff options
Diffstat (limited to 'kernel/compat.c')
-rw-r--r-- | kernel/compat.c | 64 |
1 files changed, 36 insertions, 28 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index f6c204f07ea6..c9e2ec0b34a8 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/posix-timers.h> | 25 | #include <linux/posix-timers.h> |
26 | #include <linux/times.h> | 26 | #include <linux/times.h> |
27 | #include <linux/ptrace.h> | 27 | #include <linux/ptrace.h> |
28 | #include <linux/gfp.h> | ||
28 | 29 | ||
29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
30 | 31 | ||
@@ -278,11 +279,6 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource, | |||
278 | struct compat_rlimit __user *rlim) | 279 | struct compat_rlimit __user *rlim) |
279 | { | 280 | { |
280 | struct rlimit r; | 281 | struct rlimit r; |
281 | int ret; | ||
282 | mm_segment_t old_fs = get_fs (); | ||
283 | |||
284 | if (resource >= RLIM_NLIMITS) | ||
285 | return -EINVAL; | ||
286 | 282 | ||
287 | if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || | 283 | if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || |
288 | __get_user(r.rlim_cur, &rlim->rlim_cur) || | 284 | __get_user(r.rlim_cur, &rlim->rlim_cur) || |
@@ -293,10 +289,7 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource, | |||
293 | r.rlim_cur = RLIM_INFINITY; | 289 | r.rlim_cur = RLIM_INFINITY; |
294 | if (r.rlim_max == COMPAT_RLIM_INFINITY) | 290 | if (r.rlim_max == COMPAT_RLIM_INFINITY) |
295 | r.rlim_max = RLIM_INFINITY; | 291 | r.rlim_max = RLIM_INFINITY; |
296 | set_fs(KERNEL_DS); | 292 | return do_prlimit(current, resource, &r, NULL); |
297 | ret = sys_setrlimit(resource, (struct rlimit __user *) &r); | ||
298 | set_fs(old_fs); | ||
299 | return ret; | ||
300 | } | 293 | } |
301 | 294 | ||
302 | #ifdef COMPAT_RLIM_OLD_INFINITY | 295 | #ifdef COMPAT_RLIM_OLD_INFINITY |
@@ -328,16 +321,13 @@ asmlinkage long compat_sys_old_getrlimit(unsigned int resource, | |||
328 | 321 | ||
329 | #endif | 322 | #endif |
330 | 323 | ||
331 | asmlinkage long compat_sys_getrlimit (unsigned int resource, | 324 | asmlinkage long compat_sys_getrlimit(unsigned int resource, |
332 | struct compat_rlimit __user *rlim) | 325 | struct compat_rlimit __user *rlim) |
333 | { | 326 | { |
334 | struct rlimit r; | 327 | struct rlimit r; |
335 | int ret; | 328 | int ret; |
336 | mm_segment_t old_fs = get_fs(); | ||
337 | 329 | ||
338 | set_fs(KERNEL_DS); | 330 | ret = do_prlimit(current, resource, NULL, &r); |
339 | ret = sys_getrlimit(resource, (struct rlimit __user *) &r); | ||
340 | set_fs(old_fs); | ||
341 | if (!ret) { | 331 | if (!ret) { |
342 | if (r.rlim_cur > COMPAT_RLIM_INFINITY) | 332 | if (r.rlim_cur > COMPAT_RLIM_INFINITY) |
343 | r.rlim_cur = COMPAT_RLIM_INFINITY; | 333 | r.rlim_cur = COMPAT_RLIM_INFINITY; |
@@ -494,29 +484,26 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, | |||
494 | { | 484 | { |
495 | int ret; | 485 | int ret; |
496 | cpumask_var_t mask; | 486 | cpumask_var_t mask; |
497 | unsigned long *k; | ||
498 | unsigned int min_length = cpumask_size(); | ||
499 | |||
500 | if (nr_cpu_ids <= BITS_PER_COMPAT_LONG) | ||
501 | min_length = sizeof(compat_ulong_t); | ||
502 | 487 | ||
503 | if (len < min_length) | 488 | if ((len * BITS_PER_BYTE) < nr_cpu_ids) |
489 | return -EINVAL; | ||
490 | if (len & (sizeof(compat_ulong_t)-1)) | ||
504 | return -EINVAL; | 491 | return -EINVAL; |
505 | 492 | ||
506 | if (!alloc_cpumask_var(&mask, GFP_KERNEL)) | 493 | if (!alloc_cpumask_var(&mask, GFP_KERNEL)) |
507 | return -ENOMEM; | 494 | return -ENOMEM; |
508 | 495 | ||
509 | ret = sched_getaffinity(pid, mask); | 496 | ret = sched_getaffinity(pid, mask); |
510 | if (ret < 0) | 497 | if (ret == 0) { |
511 | goto out; | 498 | size_t retlen = min_t(size_t, len, cpumask_size()); |
512 | 499 | ||
513 | k = cpumask_bits(mask); | 500 | if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8)) |
514 | ret = compat_put_bitmap(user_mask_ptr, k, min_length * 8); | 501 | ret = -EFAULT; |
515 | if (ret == 0) | 502 | else |
516 | ret = min_length; | 503 | ret = retlen; |
517 | 504 | } | |
518 | out: | ||
519 | free_cpumask_var(mask); | 505 | free_cpumask_var(mask); |
506 | |||
520 | return ret; | 507 | return ret; |
521 | } | 508 | } |
522 | 509 | ||
@@ -1139,3 +1126,24 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info) | |||
1139 | 1126 | ||
1140 | return 0; | 1127 | return 0; |
1141 | } | 1128 | } |
1129 | |||
1130 | /* | ||
1131 | * Allocate user-space memory for the duration of a single system call, | ||
1132 | * in order to marshall parameters inside a compat thunk. | ||
1133 | */ | ||
1134 | void __user *compat_alloc_user_space(unsigned long len) | ||
1135 | { | ||
1136 | void __user *ptr; | ||
1137 | |||
1138 | /* If len would occupy more than half of the entire compat space... */ | ||
1139 | if (unlikely(len > (((compat_uptr_t)~0) >> 1))) | ||
1140 | return NULL; | ||
1141 | |||
1142 | ptr = arch_compat_alloc_user_space(len); | ||
1143 | |||
1144 | if (unlikely(!access_ok(VERIFY_WRITE, ptr, len))) | ||
1145 | return NULL; | ||
1146 | |||
1147 | return ptr; | ||
1148 | } | ||
1149 | EXPORT_SYMBOL_GPL(compat_alloc_user_space); | ||