aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/compat.c')
-rw-r--r--kernel/compat.c64
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
331asmlinkage long compat_sys_getrlimit (unsigned int resource, 324asmlinkage 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 }
518out:
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 */
1134void __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}
1149EXPORT_SYMBOL_GPL(compat_alloc_user_space);