/* * 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/migrate.h>#include <linux/posix-timers.h>#include <linux/times.h>#include <linux/ptrace.h>#include <linux/gfp.h> #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){ long usec; if (get_user(o->tv_sec, &i->tv_sec) || get_user(usec, &i->tv_usec)) return -EFAULT; o->tv_nsec = usec * 1000; return 0;} static int compat_put_timeval(struct compat_timeval __user *o, struct timeval *i){ return (put_user(i->tv_sec, &o->tv_sec) || put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;} 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;} asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz){ if (tv) { struct timeval ktv; do_gettimeofday(&ktv); if (compat_put_timeval(tv, &ktv)) return -EFAULT; } if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;} asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz){ struct timespec kts; struct timezone ktz; if (tv) { if (compat_get_timeval(&kts, tv)) return -EFAULT; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);} int get_compat_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){ 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;} 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 && put_compat_timespec(&rmt, rmtp)) return -EFAULT; } return ret;} asmlinkage long compat_sys_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)) 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 && put_compat_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)));} asmlinkage long compat_sys_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;} asmlinkage long compat_sys_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));} asmlinkage long compat_sys_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);} /* * 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){ 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;} asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, compat_old_sigset_t __user *oset){ old_sigset_t s; long ret; mm_segment_t old_fs; 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;} asmlinkage long compat_sys_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 asmlinkage long compat_sys_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); 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 asmlinkage long compat_sys_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) || __put_user(r->ru_maxrss, &ru->ru_maxrss) || __put_user(r->ru_ixrss, &ru->ru_ixrss) || __put_user(r->ru_idrss, &ru->ru_idrss) || __put_user(r->ru_isrss, &ru->ru_isrss) || __put_user(r->ru_minflt, &ru->ru_minflt) || __put_user(r->ru_majflt, &ru->ru_majflt) || __put_user(r->ru_nswap, &ru->ru_nswap) || __put_user(r->ru_inblock, &ru->ru_inblock) || __put_user(r->ru_oublock, &ru->ru_oublock) || __put_user(r->ru_msgsnd, &ru->ru_msgsnd) || __put_user(r->ru_msgrcv, &ru->ru_msgrcv) || __put_user(r->ru_nsignals, &ru->ru_nsignals) || __put_user(r->ru_nvcsw, &ru->ru_nvcsw) || __put_user(r->ru_nivcsw, &ru->ru_nivcsw)) return -EFAULT; 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 longcompat_sys_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); } else { struct rusage r; int ret; unsigned int status; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_wait4(pid, (stat_addr ? (unsigned int __user *) &status : NULL), options, (struct rusage __user *) &r); set_fs (old_fs); if (ret > 0) { if (put_compat_rusage(&r, ru)) return -EFAULT; if (stat_addr && put_user(status, stat_addr)) return -EFAULT; } return ret; }} asmlinkage long compat_sys_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; long ret; mm_segment_t old_fs = get_fs(); memset(&info, 0, sizeof(info)); set_fs(KERNEL_DS); ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options, uru ? (struct rusage __user *)&ru : NULL); set_fs(old_fs); if ((ret < 0) || (info.si_signo == 0)) return ret; if (uru) { ret = put_compat_rusage(&ru, uru); if (ret) return ret; } Lines 1–500 of 1189. 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/migrate.h> #include <linux/posix-timers.h> #include <linux/times.h> #include <linux/ptrace.h> #include <linux/gfp.h> #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) { long usec; if (get_user(o->tv_sec, &i->tv_sec) || get_user(usec, &i->tv_usec)) return -EFAULT; o->tv_nsec = usec * 1000; return 0; } static int compat_put_timeval(struct compat_timeval __user *o, struct timeval *i) { return (put_user(i->tv_sec, &o->tv_sec) || put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0; } 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; } asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { if (tv) { struct timeval ktv; do_gettimeofday(&ktv); if (compat_put_timeval(tv, &ktv)) return -EFAULT; } if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0; } asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { struct timespec kts; struct timezone ktz; if (tv) { if (compat_get_timeval(&kts, tv)) return -EFAULT; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); } int get_compat_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) { 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; } 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 && put_compat_timespec(&rmt, rmtp)) return -EFAULT; } return ret; } asmlinkage long compat_sys_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)) 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 && put_compat_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))); } asmlinkage long compat_sys_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; } asmlinkage long compat_sys_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)); } asmlinkage long compat_sys_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); } /* * 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) { 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; } asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set, compat_old_sigset_t __user *oset) { old_sigset_t s; long ret; mm_segment_t old_fs; 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; } asmlinkage long compat_sys_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 asmlinkage long compat_sys_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); 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 asmlinkage long compat_sys_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) || __put_user(r->ru_maxrss, &ru->ru_maxrss) || __put_user(r->ru_ixrss, &ru->ru_ixrss) || __put_user(r->ru_idrss, &ru->ru_idrss) || __put_user(r->ru_isrss, &ru->ru_isrss) || __put_user(r->ru_minflt, &ru->ru_minflt) || __put_user(r->ru_majflt, &ru->ru_majflt) || __put_user(r->ru_nswap, &ru->ru_nswap) || __put_user(r->ru_inblock, &ru->ru_inblock) || __put_user(r->ru_oublock, &ru->ru_oublock) || __put_user(r->ru_msgsnd, &ru->ru_msgsnd) || __put_user(r->ru_msgrcv, &ru->ru_msgrcv) || __put_user(r->ru_nsignals, &ru->ru_nsignals) || __put_user(r->ru_nvcsw, &ru->ru_nvcsw) || __put_user(r->ru_nivcsw, &ru->ru_nivcsw)) return -EFAULT; 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) { if (!ru) { return sys_wait4(pid, stat_addr, options, NULL); } else { struct rusage r; int ret; unsigned int status; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_wait4(pid, (stat_addr ? (unsigned int __user *) &status : NULL), options, (struct rusage __user *) &r); set_fs (old_fs); if (ret > 0) { if (put_compat_rusage(&r, ru)) return -EFAULT; if (stat_addr && put_user(status, stat_addr)) return -EFAULT; } return ret; } } asmlinkage long compat_sys_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; long ret; mm_segment_t old_fs = get_fs(); memset(&info, 0, sizeof(info)); set_fs(KERNEL_DS); ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options, uru ? (struct rusage __user *)&ru : NULL); set_fs(old_fs); if ((ret < 0) || (info.si_signo == 0)) return ret; if (uru) { ret = put_compat_rusage(&ru, uru); if (ret) return ret; }