compat.c 15.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *  linux/kernel/compat.c
 *
 *  Kernel compatibililty routines for e.g. 32 bit syscall support
 *  on 64 bit kernels.
 *
 *  Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 */

#include <linux/linkage.h>
#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/signal.h>
#include <linux/sched.h>	/* for MAX_SCHEDULE_TIMEOUT */
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/security.h>
23
#include <linux/timex.h>
24
#include <linux/export.h>
25
#include <linux/migrate.h>
26
#include <linux/posix-timers.h>
27
#include <linux/times.h>
28
#include <linux/ptrace.h>
29
#include <linux/gfp.h>
L
Linus Torvalds 已提交
30

31
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
32

33 34 35 36 37
int compat_get_timex(struct timex *txc, const struct compat_timex __user *utp)
{
	struct compat_timex tx32;

	if (copy_from_user(&tx32, utp, sizeof(struct compat_timex)))
38 39
		return -EFAULT;

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
	txc->modes = tx32.modes;
	txc->offset = tx32.offset;
	txc->freq = tx32.freq;
	txc->maxerror = tx32.maxerror;
	txc->esterror = tx32.esterror;
	txc->status = tx32.status;
	txc->constant = tx32.constant;
	txc->precision = tx32.precision;
	txc->tolerance = tx32.tolerance;
	txc->time.tv_sec = tx32.time.tv_sec;
	txc->time.tv_usec = tx32.time.tv_usec;
	txc->tick = tx32.tick;
	txc->ppsfreq = tx32.ppsfreq;
	txc->jitter = tx32.jitter;
	txc->shift = tx32.shift;
	txc->stabil = tx32.stabil;
	txc->jitcnt = tx32.jitcnt;
	txc->calcnt = tx32.calcnt;
	txc->errcnt = tx32.errcnt;
	txc->stbcnt = tx32.stbcnt;

61 62 63
	return 0;
}

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
int compat_put_timex(struct compat_timex __user *utp, const struct timex *txc)
{
	struct compat_timex tx32;

	memset(&tx32, 0, sizeof(struct compat_timex));
	tx32.modes = txc->modes;
	tx32.offset = txc->offset;
	tx32.freq = txc->freq;
	tx32.maxerror = txc->maxerror;
	tx32.esterror = txc->esterror;
	tx32.status = txc->status;
	tx32.constant = txc->constant;
	tx32.precision = txc->precision;
	tx32.tolerance = txc->tolerance;
	tx32.time.tv_sec = txc->time.tv_sec;
	tx32.time.tv_usec = txc->time.tv_usec;
	tx32.tick = txc->tick;
	tx32.ppsfreq = txc->ppsfreq;
	tx32.jitter = txc->jitter;
	tx32.shift = txc->shift;
	tx32.stabil = txc->stabil;
	tx32.jitcnt = txc->jitcnt;
	tx32.calcnt = txc->calcnt;
	tx32.errcnt = txc->errcnt;
	tx32.stbcnt = txc->stbcnt;
	tx32.tai = txc->tai;
	if (copy_to_user(utp, &tx32, sizeof(struct compat_timex)))
91 92 93 94
		return -EFAULT;
	return 0;
}

95
static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
96 97 98 99 100 101
{
	return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
			__get_user(tv->tv_sec, &ctv->tv_sec) ||
			__get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}

102
static int __compat_put_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
103 104 105 106 107 108
{
	return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) ||
			__put_user(tv->tv_sec, &ctv->tv_sec) ||
			__put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
}

109
static int __compat_get_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
L
Linus Torvalds 已提交
110 111 112 113 114 115
{
	return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
			__get_user(ts->tv_sec, &cts->tv_sec) ||
			__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}

116
static int __compat_put_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
L
Linus Torvalds 已提交
117 118 119 120 121 122
{
	return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) ||
			__put_user(ts->tv_sec, &cts->tv_sec) ||
			__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
static int __compat_get_timespec64(struct timespec64 *ts64,
				   const struct compat_timespec __user *cts)
{
	struct compat_timespec ts;
	int ret;

	ret = copy_from_user(&ts, cts, sizeof(ts));
	if (ret)
		return -EFAULT;

	ts64->tv_sec = ts.tv_sec;
	ts64->tv_nsec = ts.tv_nsec;

	return 0;
}

static int __compat_put_timespec64(const struct timespec64 *ts64,
				   struct compat_timespec __user *cts)
{
	struct compat_timespec ts = {
		.tv_sec = ts64->tv_sec,
		.tv_nsec = ts64->tv_nsec
	};
	return copy_to_user(cts, &ts, sizeof(ts)) ? -EFAULT : 0;
}

int compat_get_timespec64(struct timespec64 *ts, const void __user *uts)
{
	if (COMPAT_USE_64BIT_TIME)
		return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0;
	else
		return __compat_get_timespec64(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_get_timespec64);

int compat_put_timespec64(const struct timespec64 *ts, void __user *uts)
{
	if (COMPAT_USE_64BIT_TIME)
		return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0;
	else
		return __compat_put_timespec64(ts, uts);
}
EXPORT_SYMBOL_GPL(compat_put_timespec64);

167 168 169
int compat_get_timeval(struct timeval *tv, const void __user *utv)
{
	if (COMPAT_USE_64BIT_TIME)
170
		return copy_from_user(tv, utv, sizeof(*tv)) ? -EFAULT : 0;
171
	else
172
		return __compat_get_timeval(tv, utv);
173 174 175 176 177 178
}
EXPORT_SYMBOL_GPL(compat_get_timeval);

int compat_put_timeval(const struct timeval *tv, void __user *utv)
{
	if (COMPAT_USE_64BIT_TIME)
179
		return copy_to_user(utv, tv, sizeof(*tv)) ? -EFAULT : 0;
180
	else
181
		return __compat_put_timeval(tv, utv);
182 183 184 185 186 187
}
EXPORT_SYMBOL_GPL(compat_put_timeval);

int compat_get_timespec(struct timespec *ts, const void __user *uts)
{
	if (COMPAT_USE_64BIT_TIME)
188
		return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0;
189
	else
190
		return __compat_get_timespec(ts, uts);
191 192 193 194 195 196
}
EXPORT_SYMBOL_GPL(compat_get_timespec);

int compat_put_timespec(const struct timespec *ts, void __user *uts)
{
	if (COMPAT_USE_64BIT_TIME)
197
		return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0;
198
	else
199
		return __compat_put_timespec(ts, uts);
200 201 202
}
EXPORT_SYMBOL_GPL(compat_put_timespec);

203
int get_compat_itimerval(struct itimerval *o, const struct compat_itimerval __user *i)
L
Linus Torvalds 已提交
204
{
205
	struct compat_itimerval v32;
206

207 208 209 210 211 212 213
	if (copy_from_user(&v32, i, sizeof(struct compat_itimerval)))
		return -EFAULT;
	o->it_interval.tv_sec = v32.it_interval.tv_sec;
	o->it_interval.tv_usec = v32.it_interval.tv_usec;
	o->it_value.tv_sec = v32.it_value.tv_sec;
	o->it_value.tv_usec = v32.it_value.tv_usec;
	return 0;
L
Linus Torvalds 已提交
214 215
}

216
int put_compat_itimerval(struct compat_itimerval __user *o, const struct itimerval *i)
L
Linus Torvalds 已提交
217
{
218
	struct compat_itimerval v32;
L
Linus Torvalds 已提交
219

220 221 222 223 224
	v32.it_interval.tv_sec = i->it_interval.tv_sec;
	v32.it_interval.tv_usec = i->it_interval.tv_usec;
	v32.it_value.tv_sec = i->it_value.tv_sec;
	v32.it_value.tv_usec = i->it_value.tv_usec;
	return copy_to_user(o, &v32, sizeof(struct compat_itimerval)) ? -EFAULT : 0;
L
Linus Torvalds 已提交
225 226
}

227 228
#ifdef __ARCH_WANT_SYS_SIGPROCMASK

229 230 231 232 233
/*
 * sys_sigprocmask SIG_SETMASK sets the first (compat) word of the
 * blocked set of signals to the supplied signal set
 */
static inline void compat_sig_setmask(sigset_t *blocked, compat_sigset_word set)
L
Linus Torvalds 已提交
234
{
235 236
	memcpy(blocked->sig, &set, sizeof(set));
}
L
Linus Torvalds 已提交
237

238 239 240
COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how,
		       compat_old_sigset_t __user *, nset,
		       compat_old_sigset_t __user *, oset)
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
{
	old_sigset_t old_set, new_set;
	sigset_t new_blocked;

	old_set = current->blocked.sig[0];

	if (nset) {
		if (get_user(new_set, nset))
			return -EFAULT;
		new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));

		new_blocked = current->blocked;

		switch (how) {
		case SIG_BLOCK:
			sigaddsetmask(&new_blocked, new_set);
			break;
		case SIG_UNBLOCK:
			sigdelsetmask(&new_blocked, new_set);
			break;
		case SIG_SETMASK:
			compat_sig_setmask(&new_blocked, new_set);
			break;
		default:
			return -EINVAL;
		}

		set_current_blocked(&new_blocked);
	}

	if (oset) {
		if (put_user(old_set, oset))
			return -EFAULT;
	}

	return 0;
L
Linus Torvalds 已提交
277 278
}

279 280
#endif

L
Linus Torvalds 已提交
281 282
int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
{
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	struct compat_rusage r32;
	memset(&r32, 0, sizeof(r32));
	r32.ru_utime.tv_sec = r->ru_utime.tv_sec;
	r32.ru_utime.tv_usec = r->ru_utime.tv_usec;
	r32.ru_stime.tv_sec = r->ru_stime.tv_sec;
	r32.ru_stime.tv_usec = r->ru_stime.tv_usec;
	r32.ru_maxrss = r->ru_maxrss;
	r32.ru_ixrss = r->ru_ixrss;
	r32.ru_idrss = r->ru_idrss;
	r32.ru_isrss = r->ru_isrss;
	r32.ru_minflt = r->ru_minflt;
	r32.ru_majflt = r->ru_majflt;
	r32.ru_nswap = r->ru_nswap;
	r32.ru_inblock = r->ru_inblock;
	r32.ru_oublock = r->ru_oublock;
	r32.ru_msgsnd = r->ru_msgsnd;
	r32.ru_msgrcv = r->ru_msgrcv;
	r32.ru_nsignals = r->ru_nsignals;
	r32.ru_nvcsw = r->ru_nvcsw;
	r32.ru_nivcsw = r->ru_nivcsw;
	if (copy_to_user(ru, &r32, sizeof(r32)))
L
Linus Torvalds 已提交
304 305 306 307 308
		return -EFAULT;
	return 0;
}

static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
R
Rusty Russell 已提交
309
				    unsigned len, struct cpumask *new_mask)
L
Linus Torvalds 已提交
310 311 312
{
	unsigned long *k;

R
Rusty Russell 已提交
313 314 315 316
	if (len < cpumask_size())
		memset(new_mask, 0, cpumask_size());
	else if (len > cpumask_size())
		len = cpumask_size();
L
Linus Torvalds 已提交
317

R
Rusty Russell 已提交
318
	k = cpumask_bits(new_mask);
L
Linus Torvalds 已提交
319 320 321
	return compat_get_bitmap(k, user_mask_ptr, len * 8);
}

322 323 324
COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid,
		       unsigned int, len,
		       compat_ulong_t __user *, user_mask_ptr)
L
Linus Torvalds 已提交
325
{
R
Rusty Russell 已提交
326
	cpumask_var_t new_mask;
L
Linus Torvalds 已提交
327 328
	int retval;

R
Rusty Russell 已提交
329 330 331 332
	if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
		return -ENOMEM;

	retval = compat_get_user_cpu_mask(user_mask_ptr, len, new_mask);
L
Linus Torvalds 已提交
333
	if (retval)
R
Rusty Russell 已提交
334
		goto out;
L
Linus Torvalds 已提交
335

R
Rusty Russell 已提交
336 337 338 339
	retval = sched_setaffinity(pid, new_mask);
out:
	free_cpumask_var(new_mask);
	return retval;
L
Linus Torvalds 已提交
340 341
}

342 343
COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t,  pid, unsigned int, len,
		       compat_ulong_t __user *, user_mask_ptr)
L
Linus Torvalds 已提交
344 345
{
	int ret;
R
Rusty Russell 已提交
346
	cpumask_var_t mask;
L
Linus Torvalds 已提交
347

348 349 350
	if ((len * BITS_PER_BYTE) < nr_cpu_ids)
		return -EINVAL;
	if (len & (sizeof(compat_ulong_t)-1))
L
Linus Torvalds 已提交
351 352
		return -EINVAL;

R
Rusty Russell 已提交
353 354 355 356
	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
		return -ENOMEM;

	ret = sched_getaffinity(pid, mask);
357 358
	if (ret == 0) {
		size_t retlen = min_t(size_t, len, cpumask_size());
L
Linus Torvalds 已提交
359

360 361 362 363 364
		if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8))
			ret = -EFAULT;
		else
			ret = retlen;
	}
R
Rusty Russell 已提交
365
	free_cpumask_var(mask);
366

R
Rusty Russell 已提交
367
	return ret;
L
Linus Torvalds 已提交
368 369
}

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
int get_compat_itimerspec64(struct itimerspec64 *its,
			const struct compat_itimerspec __user *uits)
{

	if (__compat_get_timespec64(&its->it_interval, &uits->it_interval) ||
	    __compat_get_timespec64(&its->it_value, &uits->it_value))
		return -EFAULT;
	return 0;
}
EXPORT_SYMBOL_GPL(get_compat_itimerspec64);

int put_compat_itimerspec64(const struct itimerspec64 *its,
			struct compat_itimerspec __user *uits)
{
	if (__compat_put_timespec64(&its->it_interval, &uits->it_interval) ||
	    __compat_put_timespec64(&its->it_value, &uits->it_value))
		return -EFAULT;
	return 0;
}
EXPORT_SYMBOL_GPL(put_compat_itimerspec64);

L
Linus Torvalds 已提交
391 392 393 394 395 396 397 398 399 400
/*
 * We currently only need the following fields from the sigevent
 * structure: sigev_value, sigev_signo, sig_notify and (sometimes
 * sigev_notify_thread_id).  The others are handled in user mode.
 * We also assume that copying sigev_value.sival_int is sufficient
 * to keep all the bits of sigev_value.sival_ptr intact.
 */
int get_compat_sigevent(struct sigevent *event,
		const struct compat_sigevent __user *u_event)
{
401
	memset(event, 0, sizeof(*event));
L
Linus Torvalds 已提交
402 403 404 405 406 407 408 409 410 411
	return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) ||
		__get_user(event->sigev_value.sival_int,
			&u_event->sigev_value.sival_int) ||
		__get_user(event->sigev_signo, &u_event->sigev_signo) ||
		__get_user(event->sigev_notify, &u_event->sigev_notify) ||
		__get_user(event->sigev_notify_thread_id,
			&u_event->sigev_notify_thread_id))
		? -EFAULT : 0;
}

412
long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
L
Linus Torvalds 已提交
413 414 415 416 417 418
		       unsigned long bitmap_size)
{
	unsigned long nr_compat_longs;

	/* align bitmap up to nearest compat_long_t boundary */
	bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
419
	nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
L
Linus Torvalds 已提交
420 421 422 423

	if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
		return -EFAULT;

424 425 426 427 428 429 430
	user_access_begin();
	while (nr_compat_longs > 1) {
		compat_ulong_t l1, l2;
		unsafe_get_user(l1, umask++, Efault);
		unsafe_get_user(l2, umask++, Efault);
		*mask++ = ((unsigned long)l2 << BITS_PER_COMPAT_LONG) | l1;
		nr_compat_longs -= 2;
L
Linus Torvalds 已提交
431
	}
432 433 434
	if (nr_compat_longs)
		unsafe_get_user(*mask, umask++, Efault);
	user_access_end();
L
Linus Torvalds 已提交
435
	return 0;
436 437 438 439

Efault:
	user_access_end();
	return -EFAULT;
L
Linus Torvalds 已提交
440 441 442 443 444 445 446 447 448
}

long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
		       unsigned long bitmap_size)
{
	unsigned long nr_compat_longs;

	/* align bitmap up to nearest compat_long_t boundary */
	bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
449
	nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
L
Linus Torvalds 已提交
450 451 452 453

	if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
		return -EFAULT;

454 455 456 457 458 459
	user_access_begin();
	while (nr_compat_longs > 1) {
		unsigned long m = *mask++;
		unsafe_put_user((compat_ulong_t)m, umask++, Efault);
		unsafe_put_user(m >> BITS_PER_COMPAT_LONG, umask++, Efault);
		nr_compat_longs -= 2;
L
Linus Torvalds 已提交
460
	}
461 462 463
	if (nr_compat_longs)
		unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
	user_access_end();
L
Linus Torvalds 已提交
464
	return 0;
465 466 467
Efault:
	user_access_end();
	return -EFAULT;
L
Linus Torvalds 已提交
468 469 470
}

void
A
Al Viro 已提交
471
sigset_from_compat(sigset_t *set, const compat_sigset_t *compat)
L
Linus Torvalds 已提交
472 473 474 475 476 477 478 479
{
	switch (_NSIG_WORDS) {
	case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
	case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
	case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
	case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
	}
}
480
EXPORT_SYMBOL_GPL(sigset_from_compat);
L
Linus Torvalds 已提交
481

482 483 484
int
put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set,
		  unsigned int size)
A
Al Viro 已提交
485
{
486 487 488
	/* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */
#ifdef __BIG_ENDIAN
	compat_sigset_t v;
A
Al Viro 已提交
489
	switch (_NSIG_WORDS) {
490 491 492 493
	case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3];
	case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2];
	case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1];
	case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0];
A
Al Viro 已提交
494
	}
495 496 497 498
	return copy_to_user(compat, &v, size) ? -EFAULT : 0;
#else
	return copy_to_user(compat, set, size) ? -EFAULT : 0;
#endif
A
Al Viro 已提交
499 500
}

501
#ifdef CONFIG_NUMA
502 503 504 505 506
COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
		       compat_uptr_t __user *, pages32,
		       const int __user *, nodes,
		       int __user *, status,
		       int, flags)
507 508 509 510 511 512 513 514
{
	const void __user * __user *pages;
	int i;

	pages = compat_alloc_user_space(nr_pages * sizeof(void *));
	for (i = 0; i < nr_pages; i++) {
		compat_uptr_t p;

515
		if (get_user(p, pages32 + i) ||
516 517 518 519 520
			put_user(compat_ptr(p), pages + i))
			return -EFAULT;
	}
	return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
}
521

522 523 524 525
COMPAT_SYSCALL_DEFINE4(migrate_pages, compat_pid_t, pid,
		       compat_ulong_t, maxnode,
		       const compat_ulong_t __user *, old_nodes,
		       const compat_ulong_t __user *, new_nodes)
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
{
	unsigned long __user *old = NULL;
	unsigned long __user *new = NULL;
	nodemask_t tmp_mask;
	unsigned long nr_bits;
	unsigned long size;

	nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES);
	size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
	if (old_nodes) {
		if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits))
			return -EFAULT;
		old = compat_alloc_user_space(new_nodes ? size * 2 : size);
		if (new_nodes)
			new = old + size / sizeof(unsigned long);
		if (copy_to_user(old, nodes_addr(tmp_mask), size))
			return -EFAULT;
	}
	if (new_nodes) {
		if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits))
			return -EFAULT;
		if (new == NULL)
			new = compat_alloc_user_space(size);
		if (copy_to_user(new, nodes_addr(tmp_mask), size))
			return -EFAULT;
	}
	return sys_migrate_pages(pid, nr_bits + 1, old, new);
}
554
#endif
555

556 557 558
COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval,
		       compat_pid_t, pid,
		       struct compat_timespec __user *, interval)
559 560 561 562 563 564 565 566
{
	struct timespec t;
	int ret;
	mm_segment_t old_fs = get_fs();

	set_fs(KERNEL_DS);
	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
	set_fs(old_fs);
567
	if (compat_put_timespec(&t, interval))
568 569 570 571
		return -EFAULT;
	return ret;
}

572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
/*
 * Allocate user-space memory for the duration of a single system call,
 * in order to marshall parameters inside a compat thunk.
 */
void __user *compat_alloc_user_space(unsigned long len)
{
	void __user *ptr;

	/* If len would occupy more than half of the entire compat space... */
	if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
		return NULL;

	ptr = arch_compat_alloc_user_space(len);

	if (unlikely(!access_ok(VERIFY_WRITE, ptr, len)))
		return NULL;

	return ptr;
}
EXPORT_SYMBOL_GPL(compat_alloc_user_space);