/* * 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>#include <linux/timex.h>#include <linux/export.h>#include <linux/migrate.h>#include <linux/posix-timers.h>#include <linux/times.h>#include <linux/ptrace.h>#include <linux/gfp.h> #include <asm/uaccess.h> static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp){ 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; return 0;} static int compat_put_timex(struct compat_timex __user *utp, struct timex *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)) return -EFAULT; return 0;} 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(&ktv, tv)) return -EFAULT; } if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;} COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, struct timezone __user *, tz){ struct timeval user_tv; struct timespec new_ts; struct timezone new_tz; if (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(&new_tz, tz, sizeof(*tz))) return -EFAULT; } 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;} 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;} 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; struct timespec rmt; mm_segment_t oldfs; long ret; restart->nanosleep.rmtp = (struct timespec __user *) &rmt; oldfs = get_fs(); set_fs(KERNEL_DS); ret = hrtimer_nanosleep_restart(restart); set_fs(oldfs); if (ret) { rmtp = restart->nanosleep.compat_rmtp; if (rmtp && compat_put_timespec(&rmt, rmtp)) return -EFAULT; } return ret;} 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 (compat_get_timespec(&tu, rqtp)) return -EFAULT; if (!timespec_valid(&tu)) return -EINVAL; oldfs = get_fs(); set_fs(KERNEL_DS); ret = hrtimer_nanosleep(&tu, rmtp ? (struct timespec __user *)&rmt : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC); set_fs(oldfs); if (ret) { struct restart_block *restart = ¤t_thread_info()->restart_block; restart->fn = compat_nanosleep_restart; restart->nanosleep.compat_rmtp = rmtp; if (rmtp && compat_put_timespec(&rmt, rmtp)) return -EFAULT; } return ret;} static inline long get_compat_itimerval(struct itimerval *o, struct compat_itimerval __user *i){ return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));} static inline long put_compat_itimerval(struct compat_itimerval __user *o, struct itimerval *i){ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));} COMPAT_SYSCALL_DEFINE2(getitimer, int, which, struct compat_itimerval __user *, it){ struct itimerval kit; int error; error = do_getitimer(which, &kit); if (!error && put_compat_itimerval(it, &kit)) error = -EFAULT; return error;} COMPAT_SYSCALL_DEFINE3(setitimer, int, which, struct compat_itimerval __user *, in, struct compat_itimerval __user *, out){ struct itimerval kin, kout; int error; if (in) { if (get_compat_itimerval(&kin, in)) return -EFAULT; } else memset(&kin, 0, sizeof(kin)); error = do_setitimer(which, &kin, out ? &kout : NULL); if (error || !out) return error; if (put_compat_itimerval(out, &kout)) return -EFAULT; return 0;} static compat_clock_t clock_t_to_compat_clock_t(clock_t x){ return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));} COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf){ if (tbuf) { struct tms tms; struct compat_tms tmp; do_sys_times(&tms); /* Convert our struct tms to the compat version. */ tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime); tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime); tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime); tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime); if (copy_to_user(tbuf, &tmp, sizeof(tmp))) return -EFAULT; } force_successful_syscall_return(); 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(). */ COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set){ old_sigset_t s; long ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_sigpending((old_sigset_t __user *) &s); set_fs(old_fs); if (ret == 0) ret = put_user(s, set); return ret;} #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){ memcpy(blocked->sig, &set, sizeof(set));} 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;} #endif COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct compat_rlimit __user *, rlim){ struct rlimit r; if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || __get_user(r.rlim_cur, &rlim->rlim_cur) || __get_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == COMPAT_RLIM_INFINITY) r.rlim_cur = RLIM_INFINITY; if (r.rlim_max == COMPAT_RLIM_INFINITY) r.rlim_max = RLIM_INFINITY; return do_prlimit(current, resource, &r, NULL);} #ifdef COMPAT_RLIM_OLD_INFINITY 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, (struct rlimit __user *)&r); set_fs(old_fs); if (!ret) { if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY) r.rlim_cur = COMPAT_RLIM_INFINITY; if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY) r.rlim_max = COMPAT_RLIM_INFINITY; if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) || __put_user(r.rlim_cur, &rlim->rlim_cur) || __put_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; } return ret;} #endif COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct compat_rlimit __user *, rlim){ struct rlimit r; int ret; ret = do_prlimit(current, resource, NULL, &r); if (!ret) { if (r.rlim_cur > COMPAT_RLIM_INFINITY) r.rlim_cur = COMPAT_RLIM_INFINITY; if (r.rlim_max > COMPAT_RLIM_INFINITY) r.rlim_max = COMPAT_RLIM_INFINITY; if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) || __put_user(r.rlim_cur, &rlim->rlim_cur) || __put_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; } return ret;} int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru){ if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) || __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) || __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) || __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) || __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||Lines 1–500 of 1157. Load more
/* * 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> #include <linux/timex.h> #include <linux/export.h> #include <linux/migrate.h> #include <linux/posix-timers.h> #include <linux/times.h> #include <linux/ptrace.h> #include <linux/gfp.h> #include <asm/uaccess.h> static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp) { 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; return 0; } static int compat_put_timex(struct compat_timex __user *utp, struct timex *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)) return -EFAULT; return 0; } 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(&ktv, tv)) return -EFAULT; } if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0; } COMPAT_SYSCALL_DEFINE2(settimeofday, struct compat_timeval __user *, tv, struct timezone __user *, tz) { struct timeval user_tv; struct timespec new_ts; struct timezone new_tz; if (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(&new_tz, tz, sizeof(*tz))) return -EFAULT; } 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; } 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; } 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; struct timespec rmt; mm_segment_t oldfs; long ret; restart->nanosleep.rmtp = (struct timespec __user *) &rmt; oldfs = get_fs(); set_fs(KERNEL_DS); ret = hrtimer_nanosleep_restart(restart); set_fs(oldfs); if (ret) { rmtp = restart->nanosleep.compat_rmtp; if (rmtp && compat_put_timespec(&rmt, rmtp)) return -EFAULT; } return ret; } 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 (compat_get_timespec(&tu, rqtp)) return -EFAULT; if (!timespec_valid(&tu)) return -EINVAL; oldfs = get_fs(); set_fs(KERNEL_DS); ret = hrtimer_nanosleep(&tu, rmtp ? (struct timespec __user *)&rmt : NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC); set_fs(oldfs); if (ret) { struct restart_block *restart = ¤t_thread_info()->restart_block; restart->fn = compat_nanosleep_restart; restart->nanosleep.compat_rmtp = rmtp; if (rmtp && compat_put_timespec(&rmt, rmtp)) return -EFAULT; } return ret; } static inline long get_compat_itimerval(struct itimerval *o, struct compat_itimerval __user *i) { return (!access_ok(VERIFY_READ, i, sizeof(*i)) || (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); } static inline long put_compat_itimerval(struct compat_itimerval __user *o, struct itimerval *i) { return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); } COMPAT_SYSCALL_DEFINE2(getitimer, int, which, struct compat_itimerval __user *, it) { struct itimerval kit; int error; error = do_getitimer(which, &kit); if (!error && put_compat_itimerval(it, &kit)) error = -EFAULT; return error; } COMPAT_SYSCALL_DEFINE3(setitimer, int, which, struct compat_itimerval __user *, in, struct compat_itimerval __user *, out) { struct itimerval kin, kout; int error; if (in) { if (get_compat_itimerval(&kin, in)) return -EFAULT; } else memset(&kin, 0, sizeof(kin)); error = do_setitimer(which, &kin, out ? &kout : NULL); if (error || !out) return error; if (put_compat_itimerval(out, &kout)) return -EFAULT; return 0; } static compat_clock_t clock_t_to_compat_clock_t(clock_t x) { return compat_jiffies_to_clock_t(clock_t_to_jiffies(x)); } COMPAT_SYSCALL_DEFINE1(times, struct compat_tms __user *, tbuf) { if (tbuf) { struct tms tms; struct compat_tms tmp; do_sys_times(&tms); /* Convert our struct tms to the compat version. */ tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime); tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime); tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime); tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime); if (copy_to_user(tbuf, &tmp, sizeof(tmp))) return -EFAULT; } force_successful_syscall_return(); 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(). */ COMPAT_SYSCALL_DEFINE1(sigpending, compat_old_sigset_t __user *, set) { old_sigset_t s; long ret; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_sigpending((old_sigset_t __user *) &s); set_fs(old_fs); if (ret == 0) ret = put_user(s, set); return ret; } #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) { memcpy(blocked->sig, &set, sizeof(set)); } 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; } #endif COMPAT_SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct compat_rlimit __user *, rlim) { struct rlimit r; if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) || __get_user(r.rlim_cur, &rlim->rlim_cur) || __get_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == COMPAT_RLIM_INFINITY) r.rlim_cur = RLIM_INFINITY; if (r.rlim_max == COMPAT_RLIM_INFINITY) r.rlim_max = RLIM_INFINITY; return do_prlimit(current, resource, &r, NULL); } #ifdef COMPAT_RLIM_OLD_INFINITY 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, (struct rlimit __user *)&r); set_fs(old_fs); if (!ret) { if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY) r.rlim_cur = COMPAT_RLIM_INFINITY; if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY) r.rlim_max = COMPAT_RLIM_INFINITY; if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) || __put_user(r.rlim_cur, &rlim->rlim_cur) || __put_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; } return ret; } #endif COMPAT_SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct compat_rlimit __user *, rlim) { struct rlimit r; int ret; ret = do_prlimit(current, resource, NULL, &r); if (!ret) { if (r.rlim_cur > COMPAT_RLIM_INFINITY) r.rlim_cur = COMPAT_RLIM_INFINITY; if (r.rlim_max > COMPAT_RLIM_INFINITY) r.rlim_max = COMPAT_RLIM_INFINITY; if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) || __put_user(r.rlim_cur, &rlim->rlim_cur) || __put_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; } return ret; } int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru) { if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) || __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) || __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) || __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) || __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||