diff options
Diffstat (limited to 'kernel/compat.c')
| -rw-r--r-- | kernel/compat.c | 662 | 
1 files changed, 335 insertions, 327 deletions
diff --git a/kernel/compat.c b/kernel/compat.c index c9e2ec0b34a..633394f442f 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -21,6 +21,7 @@  #include <linux/unistd.h>  #include <linux/security.h>  #include <linux/timex.h> +#include <linux/export.h>  #include <linux/migrate.h>  #include <linux/posix-timers.h>  #include <linux/times.h> @@ -29,36 +30,71 @@  #include <asm/uaccess.h> -/* - * Note that the native side is already converted to a timespec, because - * that's what we want anyway. - */ -static int compat_get_timeval(struct timespec *o, -		struct compat_timeval __user *i) +static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)  { -	long usec; +	memset(txc, 0, sizeof(struct timex)); -	if (get_user(o->tv_sec, &i->tv_sec) || -	    get_user(usec, &i->tv_usec)) +	if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) || +			__get_user(txc->modes, &utp->modes) || +			__get_user(txc->offset, &utp->offset) || +			__get_user(txc->freq, &utp->freq) || +			__get_user(txc->maxerror, &utp->maxerror) || +			__get_user(txc->esterror, &utp->esterror) || +			__get_user(txc->status, &utp->status) || +			__get_user(txc->constant, &utp->constant) || +			__get_user(txc->precision, &utp->precision) || +			__get_user(txc->tolerance, &utp->tolerance) || +			__get_user(txc->time.tv_sec, &utp->time.tv_sec) || +			__get_user(txc->time.tv_usec, &utp->time.tv_usec) || +			__get_user(txc->tick, &utp->tick) || +			__get_user(txc->ppsfreq, &utp->ppsfreq) || +			__get_user(txc->jitter, &utp->jitter) || +			__get_user(txc->shift, &utp->shift) || +			__get_user(txc->stabil, &utp->stabil) || +			__get_user(txc->jitcnt, &utp->jitcnt) || +			__get_user(txc->calcnt, &utp->calcnt) || +			__get_user(txc->errcnt, &utp->errcnt) || +			__get_user(txc->stbcnt, &utp->stbcnt))  		return -EFAULT; -	o->tv_nsec = usec * 1000; +  	return 0;  } -static int compat_put_timeval(struct compat_timeval __user *o, -		struct timeval *i) +static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)  { -	return (put_user(i->tv_sec, &o->tv_sec) || -		put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0; +	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) || +			__put_user(txc->modes, &utp->modes) || +			__put_user(txc->offset, &utp->offset) || +			__put_user(txc->freq, &utp->freq) || +			__put_user(txc->maxerror, &utp->maxerror) || +			__put_user(txc->esterror, &utp->esterror) || +			__put_user(txc->status, &utp->status) || +			__put_user(txc->constant, &utp->constant) || +			__put_user(txc->precision, &utp->precision) || +			__put_user(txc->tolerance, &utp->tolerance) || +			__put_user(txc->time.tv_sec, &utp->time.tv_sec) || +			__put_user(txc->time.tv_usec, &utp->time.tv_usec) || +			__put_user(txc->tick, &utp->tick) || +			__put_user(txc->ppsfreq, &utp->ppsfreq) || +			__put_user(txc->jitter, &utp->jitter) || +			__put_user(txc->shift, &utp->shift) || +			__put_user(txc->stabil, &utp->stabil) || +			__put_user(txc->jitcnt, &utp->jitcnt) || +			__put_user(txc->calcnt, &utp->calcnt) || +			__put_user(txc->errcnt, &utp->errcnt) || +			__put_user(txc->stbcnt, &utp->stbcnt) || +			__put_user(txc->tai, &utp->tai)) +		return -EFAULT; +	return 0;  } -asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, -		struct timezone __user *tz) +COMPAT_SYSCALL_DEFINE2(gettimeofday, struct compat_timeval __user *, tv, +		       struct timezone __user *, tz)  {  	if (tv) {  		struct timeval ktv;  		do_gettimeofday(&ktv); -		if (compat_put_timeval(tv, &ktv)) +		if (compat_put_timeval(&ktv, tv))  			return -EFAULT;  	}  	if (tz) { @@ -69,38 +105,114 @@ asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,  	return 0;  } -asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, -		struct timezone __user *tz) +COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, +		       struct timezone __user *, tz)  { -	struct timespec kts; -	struct timezone ktz; +	struct timeval user_tv; +	struct timespec	new_ts; +	struct timezone new_tz;  	if (tv) { -		if (compat_get_timeval(&kts, tv)) +		if (compat_get_timeval(&user_tv, tv))  			return -EFAULT; +		new_ts.tv_sec = user_tv.tv_sec; +		new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;  	}  	if (tz) { -		if (copy_from_user(&ktz, tz, sizeof(ktz))) +		if (copy_from_user(&new_tz, tz, sizeof(*tz)))  			return -EFAULT;  	} -	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); +	return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL); +} + +static int __compat_get_timeval(struct timeval *tv, const struct compat_timeval __user *ctv) +{ +	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;  } -int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) +static int __compat_put_timeval(const struct timeval *tv, struct compat_timeval __user *ctv) +{ +	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; +} + +static int __compat_get_timespec(struct timespec *ts, const struct compat_timespec __user *cts)  {  	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;  } -int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts) +static int __compat_put_timespec(const struct timespec *ts, struct compat_timespec __user *cts)  {  	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;  } +int compat_get_timeval(struct timeval *tv, const void __user *utv) +{ +	if (COMPAT_USE_64BIT_TIME) +		return copy_from_user(tv, utv, sizeof(*tv)) ? -EFAULT : 0; +	else +		return __compat_get_timeval(tv, utv); +} +EXPORT_SYMBOL_GPL(compat_get_timeval); + +int compat_put_timeval(const struct timeval *tv, void __user *utv) +{ +	if (COMPAT_USE_64BIT_TIME) +		return copy_to_user(utv, tv, sizeof(*tv)) ? -EFAULT : 0; +	else +		return __compat_put_timeval(tv, utv); +} +EXPORT_SYMBOL_GPL(compat_put_timeval); + +int compat_get_timespec(struct timespec *ts, const void __user *uts) +{ +	if (COMPAT_USE_64BIT_TIME) +		return copy_from_user(ts, uts, sizeof(*ts)) ? -EFAULT : 0; +	else +		return __compat_get_timespec(ts, uts); +} +EXPORT_SYMBOL_GPL(compat_get_timespec); + +int compat_put_timespec(const struct timespec *ts, void __user *uts) +{ +	if (COMPAT_USE_64BIT_TIME) +		return copy_to_user(uts, ts, sizeof(*ts)) ? -EFAULT : 0; +	else +		return __compat_put_timespec(ts, uts); +} +EXPORT_SYMBOL_GPL(compat_put_timespec); + +int compat_convert_timespec(struct timespec __user **kts, +			    const void __user *cts) +{ +	struct timespec ts; +	struct timespec __user *uts; + +	if (!cts || COMPAT_USE_64BIT_TIME) { +		*kts = (struct timespec __user *)cts; +		return 0; +	} + +	uts = compat_alloc_user_space(sizeof(ts)); +	if (!uts) +		return -EFAULT; +	if (compat_get_timespec(&ts, cts)) +		return -EFAULT; +	if (copy_to_user(uts, &ts, sizeof(ts))) +		return -EFAULT; + +	*kts = uts; +	return 0; +} +  static long compat_nanosleep_restart(struct restart_block *restart)  {  	struct compat_timespec __user *rmtp; @@ -117,21 +229,21 @@ static long compat_nanosleep_restart(struct restart_block *restart)  	if (ret) {  		rmtp = restart->nanosleep.compat_rmtp; -		if (rmtp && put_compat_timespec(&rmt, rmtp)) +		if (rmtp && compat_put_timespec(&rmt, rmtp))  			return -EFAULT;  	}  	return ret;  } -asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, -				     struct compat_timespec __user *rmtp) +COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp, +		       struct compat_timespec __user *, rmtp)  {  	struct timespec tu, rmt;  	mm_segment_t oldfs;  	long ret; -	if (get_compat_timespec(&tu, rqtp)) +	if (compat_get_timespec(&tu, rqtp))  		return -EFAULT;  	if (!timespec_valid(&tu)) @@ -151,7 +263,7 @@ asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,  		restart->fn = compat_nanosleep_restart;  		restart->nanosleep.compat_rmtp = rmtp; -		if (rmtp && put_compat_timespec(&rmt, rmtp)) +		if (rmtp && compat_put_timespec(&rmt, rmtp))  			return -EFAULT;  	} @@ -178,8 +290,8 @@ static inline long put_compat_itimerval(struct compat_itimerval __user *o,  		 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));  } -asmlinkage long compat_sys_getitimer(int which, -		struct compat_itimerval __user *it) +COMPAT_SYSCALL_DEFINE2(getitimer, int, which, +		struct compat_itimerval __user *, it)  {  	struct itimerval kit;  	int error; @@ -190,9 +302,9 @@ asmlinkage long compat_sys_getitimer(int which,  	return error;  } -asmlinkage long compat_sys_setitimer(int which, -		struct compat_itimerval __user *in, -		struct compat_itimerval __user *out) +COMPAT_SYSCALL_DEFINE3(setitimer, int, which, +		struct compat_itimerval __user *, in, +		struct compat_itimerval __user *, out)  {  	struct itimerval kin, kout;  	int error; @@ -216,7 +328,7 @@ static compat_clock_t clock_t_to_compat_clock_t(clock_t x)  	return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));  } -asmlinkage long compat_sys_times(struct compat_tms __user *tbuf) +COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf)  {  	if (tbuf) {  		struct tms tms; @@ -235,12 +347,14 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)  	return compat_jiffies_to_clock_t(jiffies);  } +#ifdef __ARCH_WANT_SYS_SIGPENDING +  /*   * Assumption: old_sigset_t and compat_old_sigset_t are both   * types that can be passed to put_user()/get_user().   */ -asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set) +COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set)  {  	old_sigset_t s;  	long ret; @@ -254,29 +368,64 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)  	return ret;  } -asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, -		compat_old_sigset_t __user *oset) +#endif + +#ifdef __ARCH_WANT_SYS_SIGPROCMASK + +/* + * 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)  { -	old_sigset_t s; -	long ret; -	mm_segment_t old_fs; +	memcpy(blocked->sig, &set, sizeof(set)); +} -	if (set && get_user(s, set)) -		return -EFAULT; -	old_fs = get_fs(); -	set_fs(KERNEL_DS); -	ret = sys_sigprocmask(how, -			      set ? (old_sigset_t __user *) &s : NULL, -			      oset ? (old_sigset_t __user *) &s : NULL); -	set_fs(old_fs); -	if (ret == 0) -		if (oset) -			ret = put_user(s, oset); -	return ret; +COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how, +		       compat_old_sigset_t __user *, nset, +		       compat_old_sigset_t __user *, oset) +{ +	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;  } -asmlinkage long compat_sys_setrlimit(unsigned int resource, -		struct compat_rlimit __user *rlim) +#endif + +COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource, +		       struct compat_rlimit __user *, rlim)  {  	struct rlimit r; @@ -294,15 +443,15 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,  #ifdef COMPAT_RLIM_OLD_INFINITY -asmlinkage long compat_sys_old_getrlimit(unsigned int resource, -		struct compat_rlimit __user *rlim) +COMPAT_SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, +		       struct compat_rlimit __user *, rlim)  {  	struct rlimit r;  	int ret;  	mm_segment_t old_fs = get_fs();  	set_fs(KERNEL_DS); -	ret = sys_old_getrlimit(resource, &r); +	ret = sys_old_getrlimit(resource, (struct rlimit __user *)&r);  	set_fs(old_fs);  	if (!ret) { @@ -321,8 +470,8 @@ asmlinkage long compat_sys_old_getrlimit(unsigned int resource,  #endif -asmlinkage long compat_sys_getrlimit(unsigned int resource, -		struct compat_rlimit __user *rlim) +COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource, +		       struct compat_rlimit __user *, rlim)  {  	struct rlimit r;  	int ret; @@ -367,28 +516,11 @@ int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)  	return 0;  } -asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru) -{ -	struct rusage r; -	int ret; -	mm_segment_t old_fs = get_fs(); - -	set_fs(KERNEL_DS); -	ret = sys_getrusage(who, (struct rusage __user *) &r); -	set_fs(old_fs); - -	if (ret) -		return ret; - -	if (put_compat_rusage(&r, ru)) -		return -EFAULT; - -	return 0; -} - -asmlinkage long -compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options, -	struct compat_rusage __user *ru) +COMPAT_SYSCALL_DEFINE4(wait4, +	compat_pid_t, pid, +	compat_uint_t __user *, stat_addr, +	int, options, +	struct compat_rusage __user *, ru)  {  	if (!ru) {  		return sys_wait4(pid, stat_addr, options, NULL); @@ -415,9 +547,10 @@ compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,  	}  } -asmlinkage long compat_sys_waitid(int which, compat_pid_t pid, -		struct compat_siginfo __user *uinfo, int options, -		struct compat_rusage __user *uru) +COMPAT_SYSCALL_DEFINE5(waitid, +		int, which, compat_pid_t, pid, +		struct compat_siginfo __user *, uinfo, int, options, +		struct compat_rusage __user *, uru)  {  	siginfo_t info;  	struct rusage ru; @@ -435,9 +568,13 @@ asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,  		return ret;  	if (uru) { -		ret = put_compat_rusage(&ru, uru); +		/* sys_waitid() overwrites everything in ru */ +		if (COMPAT_USE_64BIT_TIME) +			ret = copy_to_user(uru, &ru, sizeof(ru)); +		else +			ret = put_compat_rusage(&ru, uru);  		if (ret) -			return ret; +			return -EFAULT;  	}  	BUG_ON(info.si_code & __SI_MASK); @@ -459,9 +596,9 @@ static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,  	return compat_get_bitmap(k, user_mask_ptr, len * 8);  } -asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, -					     unsigned int len, -					     compat_ulong_t __user *user_mask_ptr) +COMPAT_SYSCALL_DEFINE3(sched_setaffinity, compat_pid_t, pid, +		       unsigned int, len, +		       compat_ulong_t __user *, user_mask_ptr)  {  	cpumask_var_t new_mask;  	int retval; @@ -479,8 +616,8 @@ out:  	return retval;  } -asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, -					     compat_ulong_t __user *user_mask_ptr) +COMPAT_SYSCALL_DEFINE3(sched_getaffinity, compat_pid_t,  pid, unsigned int, len, +		       compat_ulong_t __user *, user_mask_ptr)  {  	int ret;  	cpumask_var_t mask; @@ -510,8 +647,8 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,  int get_compat_itimerspec(struct itimerspec *dst,  			  const struct compat_itimerspec __user *src)  { -	if (get_compat_timespec(&dst->it_interval, &src->it_interval) || -	    get_compat_timespec(&dst->it_value, &src->it_value)) +	if (__compat_get_timespec(&dst->it_interval, &src->it_interval) || +	    __compat_get_timespec(&dst->it_value, &src->it_value))  		return -EFAULT;  	return 0;  } @@ -519,15 +656,15 @@ int get_compat_itimerspec(struct itimerspec *dst,  int put_compat_itimerspec(struct compat_itimerspec __user *dst,  			  const struct itimerspec *src)  { -	if (put_compat_timespec(&src->it_interval, &dst->it_interval) || -	    put_compat_timespec(&src->it_value, &dst->it_value)) +	if (__compat_put_timespec(&src->it_interval, &dst->it_interval) || +	    __compat_put_timespec(&src->it_value, &dst->it_value))  		return -EFAULT;  	return 0;  } -long compat_sys_timer_create(clockid_t which_clock, -			struct compat_sigevent __user *timer_event_spec, -			timer_t __user *created_timer_id) +COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock, +		       struct compat_sigevent __user *, timer_event_spec, +		       timer_t __user *, created_timer_id)  {  	struct sigevent __user *event = NULL; @@ -543,9 +680,9 @@ long compat_sys_timer_create(clockid_t which_clock,  	return sys_timer_create(which_clock, event, created_timer_id);  } -long compat_sys_timer_settime(timer_t timer_id, int flags, -			  struct compat_itimerspec __user *new, -			  struct compat_itimerspec __user *old) +COMPAT_SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, +		       struct compat_itimerspec __user *, new, +		       struct compat_itimerspec __user *, old)  {  	long err;  	mm_segment_t oldfs; @@ -566,8 +703,8 @@ long compat_sys_timer_settime(timer_t timer_id, int flags,  	return err;  } -long compat_sys_timer_gettime(timer_t timer_id, -		struct compat_itimerspec __user *setting) +COMPAT_SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, +		       struct compat_itimerspec __user *, setting)  {  	long err;  	mm_segment_t oldfs; @@ -583,14 +720,14 @@ long compat_sys_timer_gettime(timer_t timer_id,  	return err;  } -long compat_sys_clock_settime(clockid_t which_clock, -		struct compat_timespec __user *tp) +COMPAT_SYSCALL_DEFINE2(clock_settime, clockid_t, which_clock, +		       struct compat_timespec __user *, tp)  {  	long err;  	mm_segment_t oldfs;  	struct timespec ts; -	if (get_compat_timespec(&ts, tp)) +	if (compat_get_timespec(&ts, tp))  		return -EFAULT;  	oldfs = get_fs();  	set_fs(KERNEL_DS); @@ -600,8 +737,8 @@ long compat_sys_clock_settime(clockid_t which_clock,  	return err;  } -long compat_sys_clock_gettime(clockid_t which_clock, -		struct compat_timespec __user *tp) +COMPAT_SYSCALL_DEFINE2(clock_gettime, clockid_t, which_clock, +		       struct compat_timespec __user *, tp)  {  	long err;  	mm_segment_t oldfs; @@ -612,13 +749,36 @@ long compat_sys_clock_gettime(clockid_t which_clock,  	err = sys_clock_gettime(which_clock,  				(struct timespec __user *) &ts);  	set_fs(oldfs); -	if (!err && put_compat_timespec(&ts, tp)) +	if (!err && compat_put_timespec(&ts, tp))  		return -EFAULT;  	return err;  } -long compat_sys_clock_getres(clockid_t which_clock, -		struct compat_timespec __user *tp) +COMPAT_SYSCALL_DEFINE2(clock_adjtime, clockid_t, which_clock, +		       struct compat_timex __user *, utp) +{ +	struct timex txc; +	mm_segment_t oldfs; +	int err, ret; + +	err = compat_get_timex(&txc, utp); +	if (err) +		return err; + +	oldfs = get_fs(); +	set_fs(KERNEL_DS); +	ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc); +	set_fs(oldfs); + +	err = compat_put_timex(utp, &txc); +	if (err) +		return err; + +	return ret; +} + +COMPAT_SYSCALL_DEFINE2(clock_getres, clockid_t, which_clock, +		       struct compat_timespec __user *, tp)  {  	long err;  	mm_segment_t oldfs; @@ -629,7 +789,7 @@ long compat_sys_clock_getres(clockid_t which_clock,  	err = sys_clock_getres(which_clock,  			       (struct timespec __user *) &ts);  	set_fs(oldfs); -	if (!err && tp && put_compat_timespec(&ts, tp)) +	if (!err && tp && compat_put_timespec(&ts, tp))  		return -EFAULT;  	return err;  } @@ -639,7 +799,7 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)  	long err;  	mm_segment_t oldfs;  	struct timespec tu; -	struct compat_timespec *rmtp = restart->nanosleep.compat_rmtp; +	struct compat_timespec __user *rmtp = restart->nanosleep.compat_rmtp;  	restart->nanosleep.rmtp = (struct timespec __user *) &tu;  	oldfs = get_fs(); @@ -648,7 +808,7 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)  	set_fs(oldfs);  	if ((err == -ERESTART_RESTARTBLOCK) && rmtp && -	    put_compat_timespec(&tu, rmtp)) +	    compat_put_timespec(&tu, rmtp))  		return -EFAULT;  	if (err == -ERESTART_RESTARTBLOCK) { @@ -658,16 +818,16 @@ static long compat_clock_nanosleep_restart(struct restart_block *restart)  	return err;  } -long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, -			    struct compat_timespec __user *rqtp, -			    struct compat_timespec __user *rmtp) +COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, +		       struct compat_timespec __user *, rqtp, +		       struct compat_timespec __user *, rmtp)  {  	long err;  	mm_segment_t oldfs;  	struct timespec in, out;  	struct restart_block *restart; -	if (get_compat_timespec(&in, rqtp)) +	if (compat_get_timespec(&in, rqtp))  		return -EFAULT;  	oldfs = get_fs(); @@ -678,7 +838,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,  	set_fs(oldfs);  	if ((err == -ERESTART_RESTARTBLOCK) && rmtp && -	    put_compat_timespec(&out, rmtp)) +	    compat_put_timespec(&out, rmtp))  		return -EFAULT;  	if (err == -ERESTART_RESTARTBLOCK) { @@ -792,7 +952,7 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,  }  void -sigset_from_compat (sigset_t *set, compat_sigset_t *compat) +sigset_from_compat(sigset_t *set, const compat_sigset_t *compat)  {  	switch (_NSIG_WORDS) {  	case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); @@ -801,18 +961,28 @@ sigset_from_compat (sigset_t *set, compat_sigset_t *compat)  	case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );  	}  } +EXPORT_SYMBOL_GPL(sigset_from_compat); -asmlinkage long -compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, -		struct compat_siginfo __user *uinfo, -		struct compat_timespec __user *uts, compat_size_t sigsetsize) +void +sigset_to_compat(compat_sigset_t *compat, const sigset_t *set) +{ +	switch (_NSIG_WORDS) { +	case 4: compat->sig[7] = (set->sig[3] >> 32); compat->sig[6] = set->sig[3]; +	case 3: compat->sig[5] = (set->sig[2] >> 32); compat->sig[4] = set->sig[2]; +	case 2: compat->sig[3] = (set->sig[1] >> 32); compat->sig[2] = set->sig[1]; +	case 1: compat->sig[1] = (set->sig[0] >> 32); compat->sig[0] = set->sig[0]; +	} +} + +COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, +		struct compat_siginfo __user *, uinfo, +		struct compat_timespec __user *, uts, compat_size_t, sigsetsize)  {  	compat_sigset_t s32;  	sigset_t s; -	int sig;  	struct timespec t;  	siginfo_t info; -	long ret, timeout = 0; +	long ret;  	if (sigsetsize != sizeof(sigset_t))  		return -EINVAL; @@ -820,71 +990,27 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,  	if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))  		return -EFAULT;  	sigset_from_compat(&s, &s32); -	sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP)); -	signotset(&s);  	if (uts) { -		if (get_compat_timespec (&t, uts)) +		if (compat_get_timespec(&t, uts))  			return -EFAULT; -		if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 -				|| t.tv_sec < 0) -			return -EINVAL;  	} -	spin_lock_irq(¤t->sighand->siglock); -	sig = dequeue_signal(current, &s, &info); -	if (!sig) { -		timeout = MAX_SCHEDULE_TIMEOUT; -		if (uts) -			timeout = timespec_to_jiffies(&t) -				+(t.tv_sec || t.tv_nsec); -		if (timeout) { -			current->real_blocked = current->blocked; -			sigandsets(¤t->blocked, ¤t->blocked, &s); - -			recalc_sigpending(); -			spin_unlock_irq(¤t->sighand->siglock); - -			timeout = schedule_timeout_interruptible(timeout); - -			spin_lock_irq(¤t->sighand->siglock); -			sig = dequeue_signal(current, &s, &info); -			current->blocked = current->real_blocked; -			siginitset(¤t->real_blocked, 0); -			recalc_sigpending(); -		} -	} -	spin_unlock_irq(¤t->sighand->siglock); +	ret = do_sigtimedwait(&s, &info, uts ? &t : NULL); -	if (sig) { -		ret = sig; -		if (uinfo) { -			if (copy_siginfo_to_user32(uinfo, &info)) -				ret = -EFAULT; -		} -	}else { -		ret = timeout?-EINTR:-EAGAIN; +	if (ret > 0 && uinfo) { +		if (copy_siginfo_to_user32(uinfo, &info)) +			ret = -EFAULT;  	} -	return ret; -} - -asmlinkage long -compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig, -			     struct compat_siginfo __user *uinfo) -{ -	siginfo_t info; - -	if (copy_siginfo_from_user32(&info, uinfo)) -		return -EFAULT; -	return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); +	return ret;  }  #ifdef __ARCH_WANT_COMPAT_SYS_TIME  /* compat_time_t is a 32 bit "long" and needs to get converted. */ -asmlinkage long compat_sys_time(compat_time_t __user * tloc) +COMPAT_SYSCALL_DEFINE1(time, compat_time_t __user *, tloc)  {  	compat_time_t i;  	struct timeval tv; @@ -900,7 +1026,7 @@ asmlinkage long compat_sys_time(compat_time_t __user * tloc)  	return i;  } -asmlinkage long compat_sys_stime(compat_time_t __user *tptr) +COMPAT_SYSCALL_DEFINE1(stime, compat_time_t __user *, tptr)  {  	struct timespec tv;  	int err; @@ -920,99 +1046,30 @@ asmlinkage long compat_sys_stime(compat_time_t __user *tptr)  #endif /* __ARCH_WANT_COMPAT_SYS_TIME */ -#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND -asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize) -{ -	sigset_t newset; -	compat_sigset_t newset32; - -	/* XXX: Don't preclude handling different sized sigset_t's.  */ -	if (sigsetsize != sizeof(sigset_t)) -		return -EINVAL; - -	if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) -		return -EFAULT; -	sigset_from_compat(&newset, &newset32); -	sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); - -	spin_lock_irq(¤t->sighand->siglock); -	current->saved_sigmask = current->blocked; -	current->blocked = newset; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); - -	current->state = TASK_INTERRUPTIBLE; -	schedule(); -	set_restore_sigmask(); -	return -ERESTARTNOHAND; -} -#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */ - -asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp) +COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user *, utp)  {  	struct timex txc; -	int ret; +	int err, ret; -	memset(&txc, 0, sizeof(struct timex)); - -	if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) || -			__get_user(txc.modes, &utp->modes) || -			__get_user(txc.offset, &utp->offset) || -			__get_user(txc.freq, &utp->freq) || -			__get_user(txc.maxerror, &utp->maxerror) || -			__get_user(txc.esterror, &utp->esterror) || -			__get_user(txc.status, &utp->status) || -			__get_user(txc.constant, &utp->constant) || -			__get_user(txc.precision, &utp->precision) || -			__get_user(txc.tolerance, &utp->tolerance) || -			__get_user(txc.time.tv_sec, &utp->time.tv_sec) || -			__get_user(txc.time.tv_usec, &utp->time.tv_usec) || -			__get_user(txc.tick, &utp->tick) || -			__get_user(txc.ppsfreq, &utp->ppsfreq) || -			__get_user(txc.jitter, &utp->jitter) || -			__get_user(txc.shift, &utp->shift) || -			__get_user(txc.stabil, &utp->stabil) || -			__get_user(txc.jitcnt, &utp->jitcnt) || -			__get_user(txc.calcnt, &utp->calcnt) || -			__get_user(txc.errcnt, &utp->errcnt) || -			__get_user(txc.stbcnt, &utp->stbcnt)) -		return -EFAULT; +	err = compat_get_timex(&txc, utp); +	if (err) +		return err;  	ret = do_adjtimex(&txc); -	if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) || -			__put_user(txc.modes, &utp->modes) || -			__put_user(txc.offset, &utp->offset) || -			__put_user(txc.freq, &utp->freq) || -			__put_user(txc.maxerror, &utp->maxerror) || -			__put_user(txc.esterror, &utp->esterror) || -			__put_user(txc.status, &utp->status) || -			__put_user(txc.constant, &utp->constant) || -			__put_user(txc.precision, &utp->precision) || -			__put_user(txc.tolerance, &utp->tolerance) || -			__put_user(txc.time.tv_sec, &utp->time.tv_sec) || -			__put_user(txc.time.tv_usec, &utp->time.tv_usec) || -			__put_user(txc.tick, &utp->tick) || -			__put_user(txc.ppsfreq, &utp->ppsfreq) || -			__put_user(txc.jitter, &utp->jitter) || -			__put_user(txc.shift, &utp->shift) || -			__put_user(txc.stabil, &utp->stabil) || -			__put_user(txc.jitcnt, &utp->jitcnt) || -			__put_user(txc.calcnt, &utp->calcnt) || -			__put_user(txc.errcnt, &utp->errcnt) || -			__put_user(txc.stbcnt, &utp->stbcnt) || -			__put_user(txc.tai, &utp->tai)) -		ret = -EFAULT; +	err = compat_put_timex(utp, &txc); +	if (err) +		return err;  	return ret;  }  #ifdef CONFIG_NUMA -asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, -		compat_uptr_t __user *pages32, -		const int __user *nodes, -		int __user *status, -		int flags) +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)  {  	const void __user * __user *pages;  	int i; @@ -1028,10 +1085,10 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,  	return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);  } -asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, -			compat_ulong_t maxnode, -			const compat_ulong_t __user *old_nodes, -			const compat_ulong_t __user *new_nodes) +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)  {  	unsigned long __user *old = NULL;  	unsigned long __user *new = NULL; @@ -1062,69 +1119,20 @@ asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,  }  #endif -struct compat_sysinfo { -	s32 uptime; -	u32 loads[3]; -	u32 totalram; -	u32 freeram; -	u32 sharedram; -	u32 bufferram; -	u32 totalswap; -	u32 freeswap; -	u16 procs; -	u16 pad; -	u32 totalhigh; -	u32 freehigh; -	u32 mem_unit; -	char _f[20-2*sizeof(u32)-sizeof(int)]; -}; - -asmlinkage long -compat_sys_sysinfo(struct compat_sysinfo __user *info) +COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval, +		       compat_pid_t, pid, +		       struct compat_timespec __user *, interval)  { -	struct sysinfo s; - -	do_sysinfo(&s); - -	/* Check to see if any memory value is too large for 32-bit and scale -	 *  down if needed -	 */ -	if ((s.totalram >> 32) || (s.totalswap >> 32)) { -		int bitcount = 0; - -		while (s.mem_unit < PAGE_SIZE) { -			s.mem_unit <<= 1; -			bitcount++; -		} - -		s.totalram >>= bitcount; -		s.freeram >>= bitcount; -		s.sharedram >>= bitcount; -		s.bufferram >>= bitcount; -		s.totalswap >>= bitcount; -		s.freeswap >>= bitcount; -		s.totalhigh >>= bitcount; -		s.freehigh >>= bitcount; -	} +	struct timespec t; +	int ret; +	mm_segment_t old_fs = get_fs(); -	if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) || -	    __put_user (s.uptime, &info->uptime) || -	    __put_user (s.loads[0], &info->loads[0]) || -	    __put_user (s.loads[1], &info->loads[1]) || -	    __put_user (s.loads[2], &info->loads[2]) || -	    __put_user (s.totalram, &info->totalram) || -	    __put_user (s.freeram, &info->freeram) || -	    __put_user (s.sharedram, &info->sharedram) || -	    __put_user (s.bufferram, &info->bufferram) || -	    __put_user (s.totalswap, &info->totalswap) || -	    __put_user (s.freeswap, &info->freeswap) || -	    __put_user (s.procs, &info->procs) || -	    __put_user (s.totalhigh, &info->totalhigh) || -	    __put_user (s.freehigh, &info->freehigh) || -	    __put_user (s.mem_unit, &info->mem_unit)) +	set_fs(KERNEL_DS); +	ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); +	set_fs(old_fs); +	if (compat_put_timespec(&t, interval))  		return -EFAULT; - -	return 0; +	return ret;  }  /*  | 
