Root/kernel/compat.c

1/*
2 * linux/kernel/compat.c
3 *
4 * Kernel compatibililty routines for e.g. 32 bit syscall support
5 * on 64 bit kernels.
6 *
7 * Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/linkage.h>
15#include <linux/compat.h>
16#include <linux/errno.h>
17#include <linux/time.h>
18#include <linux/signal.h>
19#include <linux/sched.h> /* for MAX_SCHEDULE_TIMEOUT */
20#include <linux/syscalls.h>
21#include <linux/unistd.h>
22#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>
30
31#include <asm/uaccess.h>
32
33/*
34 * Get/set struct timeval with struct timespec on the native side
35 */
36static int compat_get_timeval_convert(struct timespec *o,
37                      struct compat_timeval __user *i)
38{
39    long usec;
40
41    if (get_user(o->tv_sec, &i->tv_sec) ||
42        get_user(usec, &i->tv_usec))
43        return -EFAULT;
44    o->tv_nsec = usec * 1000;
45    return 0;
46}
47
48static int compat_put_timeval_convert(struct compat_timeval __user *o,
49                      struct timeval *i)
50{
51    return (put_user(i->tv_sec, &o->tv_sec) ||
52        put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
53}
54
55static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
56{
57    memset(txc, 0, sizeof(struct timex));
58
59    if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
60            __get_user(txc->modes, &utp->modes) ||
61            __get_user(txc->offset, &utp->offset) ||
62            __get_user(txc->freq, &utp->freq) ||
63            __get_user(txc->maxerror, &utp->maxerror) ||
64            __get_user(txc->esterror, &utp->esterror) ||
65            __get_user(txc->status, &utp->status) ||
66            __get_user(txc->constant, &utp->constant) ||
67            __get_user(txc->precision, &utp->precision) ||
68            __get_user(txc->tolerance, &utp->tolerance) ||
69            __get_user(txc->time.tv_sec, &utp->time.tv_sec) ||
70            __get_user(txc->time.tv_usec, &utp->time.tv_usec) ||
71            __get_user(txc->tick, &utp->tick) ||
72            __get_user(txc->ppsfreq, &utp->ppsfreq) ||
73            __get_user(txc->jitter, &utp->jitter) ||
74            __get_user(txc->shift, &utp->shift) ||
75            __get_user(txc->stabil, &utp->stabil) ||
76            __get_user(txc->jitcnt, &utp->jitcnt) ||
77            __get_user(txc->calcnt, &utp->calcnt) ||
78            __get_user(txc->errcnt, &utp->errcnt) ||
79            __get_user(txc->stbcnt, &utp->stbcnt))
80        return -EFAULT;
81
82    return 0;
83}
84
85static int compat_put_timex(struct compat_timex __user *utp, struct timex *txc)
86{
87    if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
88            __put_user(txc->modes, &utp->modes) ||
89            __put_user(txc->offset, &utp->offset) ||
90            __put_user(txc->freq, &utp->freq) ||
91            __put_user(txc->maxerror, &utp->maxerror) ||
92            __put_user(txc->esterror, &utp->esterror) ||
93            __put_user(txc->status, &utp->status) ||
94            __put_user(txc->constant, &utp->constant) ||
95            __put_user(txc->precision, &utp->precision) ||
96            __put_user(txc->tolerance, &utp->tolerance) ||
97            __put_user(txc->time.tv_sec, &utp->time.tv_sec) ||
98            __put_user(txc->time.tv_usec, &utp->time.tv_usec) ||
99            __put_user(txc->tick, &utp->tick) ||
100            __put_user(txc->ppsfreq, &utp->ppsfreq) ||
101            __put_user(txc->jitter, &utp->jitter) ||
102            __put_user(txc->shift, &utp->shift) ||
103            __put_user(txc->stabil, &utp->stabil) ||
104            __put_user(txc->jitcnt, &utp->jitcnt) ||
105            __put_user(txc->calcnt, &utp->calcnt) ||
106            __put_user(txc->errcnt, &utp->errcnt) ||
107            __put_user(txc->stbcnt, &utp->stbcnt) ||
108            __put_user(txc->tai, &utp->tai))
109        return -EFAULT;
110    return 0;
111}
112
113asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
114        struct timezone __user *tz)
115{
116    if (tv) {
117        struct timeval ktv;
118        do_gettimeofday(&ktv);
119        if (compat_put_timeval_convert(tv, &ktv))
120            return -EFAULT;
121    }
122    if (tz) {
123        if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
124            return -EFAULT;
125    }
126
127    return 0;
128}
129
130asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
131        struct timezone __user *tz)
132{
133    struct timespec kts;
134    struct timezone ktz;
135
136    if (tv) {
137        if (compat_get_timeval_convert(&kts, tv))
138            return -EFAULT;
139    }
140    if (tz) {
141        if (copy_from_user(&ktz, tz, sizeof(ktz)))
142            return -EFAULT;
143    }
144
145    return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
146}
147
148int get_compat_timeval(struct timeval *tv, const struct compat_timeval __user *ctv)
149{
150    return (!access_ok(VERIFY_READ, ctv, sizeof(*ctv)) ||
151            __get_user(tv->tv_sec, &ctv->tv_sec) ||
152            __get_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
153}
154EXPORT_SYMBOL_GPL(get_compat_timeval);
155
156int put_compat_timeval(const struct timeval *tv, struct compat_timeval __user *ctv)
157{
158    return (!access_ok(VERIFY_WRITE, ctv, sizeof(*ctv)) ||
159            __put_user(tv->tv_sec, &ctv->tv_sec) ||
160            __put_user(tv->tv_usec, &ctv->tv_usec)) ? -EFAULT : 0;
161}
162EXPORT_SYMBOL_GPL(put_compat_timeval);
163
164int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
165{
166    return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
167            __get_user(ts->tv_sec, &cts->tv_sec) ||
168            __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
169}
170EXPORT_SYMBOL_GPL(get_compat_timespec);
171
172int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
173{
174    return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) ||
175            __put_user(ts->tv_sec, &cts->tv_sec) ||
176            __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
177}
178EXPORT_SYMBOL_GPL(put_compat_timespec);
179
180int compat_get_timeval(struct timeval *tv, const void __user *utv)
181{
182    if (COMPAT_USE_64BIT_TIME)
183        return copy_from_user(tv, utv, sizeof *tv) ? -EFAULT : 0;
184    else
185        return get_compat_timeval(tv, utv);
186}
187EXPORT_SYMBOL_GPL(compat_get_timeval);
188
189int compat_put_timeval(const struct timeval *tv, void __user *utv)
190{
191    if (COMPAT_USE_64BIT_TIME)
192        return copy_to_user(utv, tv, sizeof *tv) ? -EFAULT : 0;
193    else
194        return put_compat_timeval(tv, utv);
195}
196EXPORT_SYMBOL_GPL(compat_put_timeval);
197
198int compat_get_timespec(struct timespec *ts, const void __user *uts)
199{
200    if (COMPAT_USE_64BIT_TIME)
201        return copy_from_user(ts, uts, sizeof *ts) ? -EFAULT : 0;
202    else
203        return get_compat_timespec(ts, uts);
204}
205EXPORT_SYMBOL_GPL(compat_get_timespec);
206
207int compat_put_timespec(const struct timespec *ts, void __user *uts)
208{
209    if (COMPAT_USE_64BIT_TIME)
210        return copy_to_user(uts, ts, sizeof *ts) ? -EFAULT : 0;
211    else
212        return put_compat_timespec(ts, uts);
213}
214EXPORT_SYMBOL_GPL(compat_put_timespec);
215
216static long compat_nanosleep_restart(struct restart_block *restart)
217{
218    struct compat_timespec __user *rmtp;
219    struct timespec rmt;
220    mm_segment_t oldfs;
221    long ret;
222
223    restart->nanosleep.rmtp = (struct timespec __user *) &rmt;
224    oldfs = get_fs();
225    set_fs(KERNEL_DS);
226    ret = hrtimer_nanosleep_restart(restart);
227    set_fs(oldfs);
228
229    if (ret) {
230        rmtp = restart->nanosleep.compat_rmtp;
231
232        if (rmtp && put_compat_timespec(&rmt, rmtp))
233            return -EFAULT;
234    }
235
236    return ret;
237}
238
239asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
240                     struct compat_timespec __user *rmtp)
241{
242    struct timespec tu, rmt;
243    mm_segment_t oldfs;
244    long ret;
245
246    if (get_compat_timespec(&tu, rqtp))
247        return -EFAULT;
248
249    if (!timespec_valid(&tu))
250        return -EINVAL;
251
252    oldfs = get_fs();
253    set_fs(KERNEL_DS);
254    ret = hrtimer_nanosleep(&tu,
255                rmtp ? (struct timespec __user *)&rmt : NULL,
256                HRTIMER_MODE_REL, CLOCK_MONOTONIC);
257    set_fs(oldfs);
258
259    if (ret) {
260        struct restart_block *restart
261            = &current_thread_info()->restart_block;
262
263        restart->fn = compat_nanosleep_restart;
264        restart->nanosleep.compat_rmtp = rmtp;
265
266        if (rmtp && put_compat_timespec(&rmt, rmtp))
267            return -EFAULT;
268    }
269
270    return ret;
271}
272
273static inline long get_compat_itimerval(struct itimerval *o,
274        struct compat_itimerval __user *i)
275{
276    return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
277        (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
278         __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
279         __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
280         __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
281}
282
283static inline long put_compat_itimerval(struct compat_itimerval __user *o,
284        struct itimerval *i)
285{
286    return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
287        (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
288         __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
289         __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
290         __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
291}
292
293asmlinkage long compat_sys_getitimer(int which,
294        struct compat_itimerval __user *it)
295{
296    struct itimerval kit;
297    int error;
298
299    error = do_getitimer(which, &kit);
300    if (!error && put_compat_itimerval(it, &kit))
301        error = -EFAULT;
302    return error;
303}
304
305asmlinkage long compat_sys_setitimer(int which,
306        struct compat_itimerval __user *in,
307        struct compat_itimerval __user *out)
308{
309    struct itimerval kin, kout;
310    int error;
311
312    if (in) {
313        if (get_compat_itimerval(&kin, in))
314            return -EFAULT;
315    } else
316        memset(&kin, 0, sizeof(kin));
317
318    error = do_setitimer(which, &kin, out ? &kout : NULL);
319    if (error || !out)
320        return error;
321    if (put_compat_itimerval(out, &kout))
322        return -EFAULT;
323    return 0;
324}
325
326static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
327{
328    return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
329}
330
331asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
332{
333    if (tbuf) {
334        struct tms tms;
335        struct compat_tms tmp;
336
337        do_sys_times(&tms);
338        /* Convert our struct tms to the compat version. */
339        tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
340        tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
341        tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
342        tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
343        if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
344            return -EFAULT;
345    }
346    force_successful_syscall_return();
347    return compat_jiffies_to_clock_t(jiffies);
348}
349
350#ifdef __ARCH_WANT_SYS_SIGPENDING
351
352/*
353 * Assumption: old_sigset_t and compat_old_sigset_t are both
354 * types that can be passed to put_user()/get_user().
355 */
356
357asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
358{
359    old_sigset_t s;
360    long ret;
361    mm_segment_t old_fs = get_fs();
362
363    set_fs(KERNEL_DS);
364    ret = sys_sigpending((old_sigset_t __user *) &s);
365    set_fs(old_fs);
366    if (ret == 0)
367        ret = put_user(s, set);
368    return ret;
369}
370
371#endif
372
373#ifdef __ARCH_WANT_SYS_SIGPROCMASK
374
375/*
376 * sys_sigprocmask SIG_SETMASK sets the first (compat) word of the
377 * blocked set of signals to the supplied signal set
378 */
379static inline void compat_sig_setmask(sigset_t *blocked, compat_sigset_word set)
380{
381    memcpy(blocked->sig, &set, sizeof(set));
382}
383
384asmlinkage long compat_sys_sigprocmask(int how,
385                       compat_old_sigset_t __user *nset,
386                       compat_old_sigset_t __user *oset)
387{
388    old_sigset_t old_set, new_set;
389    sigset_t new_blocked;
390
391    old_set = current->blocked.sig[0];
392
393    if (nset) {
394        if (get_user(new_set, nset))
395            return -EFAULT;
396        new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
397
398        new_blocked = current->blocked;
399
400        switch (how) {
401        case SIG_BLOCK:
402            sigaddsetmask(&new_blocked, new_set);
403            break;
404        case SIG_UNBLOCK:
405            sigdelsetmask(&new_blocked, new_set);
406            break;
407        case SIG_SETMASK:
408            compat_sig_setmask(&new_blocked, new_set);
409            break;
410        default:
411            return -EINVAL;
412        }
413
414        set_current_blocked(&new_blocked);
415    }
416
417    if (oset) {
418        if (put_user(old_set, oset))
419            return -EFAULT;
420    }
421
422    return 0;
423}
424
425#endif
426
427asmlinkage long compat_sys_setrlimit(unsigned int resource,
428        struct compat_rlimit __user *rlim)
429{
430    struct rlimit r;
431
432    if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
433        __get_user(r.rlim_cur, &rlim->rlim_cur) ||
434        __get_user(r.rlim_max, &rlim->rlim_max))
435        return -EFAULT;
436
437    if (r.rlim_cur == COMPAT_RLIM_INFINITY)
438        r.rlim_cur = RLIM_INFINITY;
439    if (r.rlim_max == COMPAT_RLIM_INFINITY)
440        r.rlim_max = RLIM_INFINITY;
441    return do_prlimit(current, resource, &r, NULL);
442}
443
444#ifdef COMPAT_RLIM_OLD_INFINITY
445
446asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
447        struct compat_rlimit __user *rlim)
448{
449    struct rlimit r;
450    int ret;
451    mm_segment_t old_fs = get_fs();
452
453    set_fs(KERNEL_DS);
454    ret = sys_old_getrlimit(resource, &r);
455    set_fs(old_fs);
456
457    if (!ret) {
458        if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
459            r.rlim_cur = COMPAT_RLIM_INFINITY;
460        if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
461            r.rlim_max = COMPAT_RLIM_INFINITY;
462
463        if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
464            __put_user(r.rlim_cur, &rlim->rlim_cur) ||
465            __put_user(r.rlim_max, &rlim->rlim_max))
466            return -EFAULT;
467    }
468    return ret;
469}
470
471#endif
472
473asmlinkage long compat_sys_getrlimit(unsigned int resource,
474        struct compat_rlimit __user *rlim)
475{
476    struct rlimit r;
477    int ret;
478
479    ret = do_prlimit(current, resource, NULL, &r);
480    if (!ret) {
481        if (r.rlim_cur > COMPAT_RLIM_INFINITY)
482            r.rlim_cur = COMPAT_RLIM_INFINITY;
483        if (r.rlim_max > COMPAT_RLIM_INFINITY)
484            r.rlim_max = COMPAT_RLIM_INFINITY;
485
486        if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
487            __put_user(r.rlim_cur, &rlim->rlim_cur) ||
488            __put_user(r.rlim_max, &rlim->rlim_max))
489            return -EFAULT;
490    }
491    return ret;
492}
493
494int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
495{
496    if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
497        __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
498        __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
499        __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
500        __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
501        __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
502        __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
503        __put_user(r->ru_idrss, &ru->ru_idrss) ||
504        __put_user(r->ru_isrss, &ru->ru_isrss) ||
505        __put_user(r->ru_minflt, &ru->ru_minflt) ||
506        __put_user(r->ru_majflt, &ru->ru_majflt) ||
507        __put_user(r->ru_nswap, &ru->ru_nswap) ||
508        __put_user(r->ru_inblock, &ru->ru_inblock) ||
509        __put_user(r->ru_oublock, &ru->ru_oublock) ||
510        __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
511        __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
512        __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
513        __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
514        __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
515        return -EFAULT;
516    return 0;
517}
518
519asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru)
520{
521    struct rusage r;
522    int ret;
523    mm_segment_t old_fs = get_fs();
524
525    set_fs(KERNEL_DS);
526    ret = sys_getrusage(who, (struct rusage __user *) &r);
527    set_fs(old_fs);
528
529    if (ret)
530        return ret;
531
532    if (put_compat_rusage(&r, ru))
533        return -EFAULT;
534
535    return 0;
536}
537
538asmlinkage long
539compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,
540    struct compat_rusage __user *ru)
541{
542    if (!ru) {
543        return sys_wait4(pid, stat_addr, options, NULL);
544    } else {
545        struct rusage r;
546        int ret;
547        unsigned int status;
548        mm_segment_t old_fs = get_fs();
549
550        set_fs (KERNEL_DS);
551        ret = sys_wait4(pid,
552                (stat_addr ?
553                 (unsigned int __user *) &status : NULL),
554                options, (struct rusage __user *) &r);
555        set_fs (old_fs);
556
557        if (ret > 0) {
558            if (put_compat_rusage(&r, ru))
559                return -EFAULT;
560            if (stat_addr && put_user(status, stat_addr))
561                return -EFAULT;
562        }
563        return ret;
564    }
565}
566
567asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
568        struct compat_siginfo __user *uinfo, int options,
569        struct compat_rusage __user *uru)
570{
571    siginfo_t info;
572    struct rusage ru;
573    long ret;
574    mm_segment_t old_fs = get_fs();
575
576    memset(&info, 0, sizeof(info));
577
578    set_fs(KERNEL_DS);
579    ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options,
580             uru ? (struct rusage __user *)&ru : NULL);
581    set_fs(old_fs);
582
583    if ((ret < 0) || (info.si_signo == 0))
584        return ret;
585
586    if (uru) {
587        ret = put_compat_rusage(&ru, uru);
588        if (ret)
589            return ret;
590    }
591
592    BUG_ON(info.si_code & __SI_MASK);
593    info.si_code |= __SI_CHLD;
594    return copy_siginfo_to_user32(uinfo, &info);
595}
596
597static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
598                    unsigned len, struct cpumask *new_mask)
599{
600    unsigned long *k;
601
602    if (len < cpumask_size())
603        memset(new_mask, 0, cpumask_size());
604    else if (len > cpumask_size())
605        len = cpumask_size();
606
607    k = cpumask_bits(new_mask);
608    return compat_get_bitmap(k, user_mask_ptr, len * 8);
609}
610
611asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
612                         unsigned int len,
613                         compat_ulong_t __user *user_mask_ptr)
614{
615    cpumask_var_t new_mask;
616    int retval;
617
618    if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
619        return -ENOMEM;
620
621    retval = compat_get_user_cpu_mask(user_mask_ptr, len, new_mask);
622    if (retval)
623        goto out;
624
625    retval = sched_setaffinity(pid, new_mask);
626out:
627    free_cpumask_var(new_mask);
628    return retval;
629}
630
631asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
632                         compat_ulong_t __user *user_mask_ptr)
633{
634    int ret;
635    cpumask_var_t mask;
636
637    if ((len * BITS_PER_BYTE) < nr_cpu_ids)
638        return -EINVAL;
639    if (len & (sizeof(compat_ulong_t)-1))
640        return -EINVAL;
641
642    if (!alloc_cpumask_var(&mask, GFP_KERNEL))
643        return -ENOMEM;
644
645    ret = sched_getaffinity(pid, mask);
646    if (ret == 0) {
647        size_t retlen = min_t(size_t, len, cpumask_size());
648
649        if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8))
650            ret = -EFAULT;
651        else
652            ret = retlen;
653    }
654    free_cpumask_var(mask);
655
656    return ret;
657}
658
659int get_compat_itimerspec(struct itimerspec *dst,
660              const struct compat_itimerspec __user *src)
661{
662    if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
663        get_compat_timespec(&dst->it_value, &src->it_value))
664        return -EFAULT;
665    return 0;
666}
667
668int put_compat_itimerspec(struct compat_itimerspec __user *dst,
669              const struct itimerspec *src)
670{
671    if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
672        put_compat_timespec(&src->it_value, &dst->it_value))
673        return -EFAULT;
674    return 0;
675}
676
677long compat_sys_timer_create(clockid_t which_clock,
678            struct compat_sigevent __user *timer_event_spec,
679            timer_t __user *created_timer_id)
680{
681    struct sigevent __user *event = NULL;
682
683    if (timer_event_spec) {
684        struct sigevent kevent;
685
686        event = compat_alloc_user_space(sizeof(*event));
687        if (get_compat_sigevent(&kevent, timer_event_spec) ||
688            copy_to_user(event, &kevent, sizeof(*event)))
689            return -EFAULT;
690    }
691
692    return sys_timer_create(which_clock, event, created_timer_id);
693}
694
695long compat_sys_timer_settime(timer_t timer_id, int flags,
696              struct compat_itimerspec __user *new,
697              struct compat_itimerspec __user *old)
698{
699    long err;
700    mm_segment_t oldfs;
701    struct itimerspec newts, oldts;
702
703    if (!new)
704        return -EINVAL;
705    if (get_compat_itimerspec(&newts, new))
706        return -EFAULT;
707    oldfs = get_fs();
708    set_fs(KERNEL_DS);
709    err = sys_timer_settime(timer_id, flags,
710                (struct itimerspec __user *) &newts,
711                (struct itimerspec __user *) &oldts);
712    set_fs(oldfs);
713    if (!err && old && put_compat_itimerspec(old, &oldts))
714        return -EFAULT;
715    return err;
716}
717
718long compat_sys_timer_gettime(timer_t timer_id,
719        struct compat_itimerspec __user *setting)
720{
721    long err;
722    mm_segment_t oldfs;
723    struct itimerspec ts;
724
725    oldfs = get_fs();
726    set_fs(KERNEL_DS);
727    err = sys_timer_gettime(timer_id,
728                (struct itimerspec __user *) &ts);
729    set_fs(oldfs);
730    if (!err && put_compat_itimerspec(setting, &ts))
731        return -EFAULT;
732    return err;
733}
734
735long compat_sys_clock_settime(clockid_t which_clock,
736        struct compat_timespec __user *tp)
737{
738    long err;
739    mm_segment_t oldfs;
740    struct timespec ts;
741
742    if (get_compat_timespec(&ts, tp))
743        return -EFAULT;
744    oldfs = get_fs();
745    set_fs(KERNEL_DS);
746    err = sys_clock_settime(which_clock,
747                (struct timespec __user *) &ts);
748    set_fs(oldfs);
749    return err;
750}
751
752long compat_sys_clock_gettime(clockid_t which_clock,
753        struct compat_timespec __user *tp)
754{
755    long err;
756    mm_segment_t oldfs;
757    struct timespec ts;
758
759    oldfs = get_fs();
760    set_fs(KERNEL_DS);
761    err = sys_clock_gettime(which_clock,
762                (struct timespec __user *) &ts);
763    set_fs(oldfs);
764    if (!err && put_compat_timespec(&ts, tp))
765        return -EFAULT;
766    return err;
767}
768
769long compat_sys_clock_adjtime(clockid_t which_clock,
770        struct compat_timex __user *utp)
771{
772    struct timex txc;
773    mm_segment_t oldfs;
774    int err, ret;
775
776    err = compat_get_timex(&txc, utp);
777    if (err)
778        return err;
779
780    oldfs = get_fs();
781    set_fs(KERNEL_DS);
782    ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
783    set_fs(oldfs);
784
785    err = compat_put_timex(utp, &txc);
786    if (err)
787        return err;
788
789    return ret;
790}
791
792long compat_sys_clock_getres(clockid_t which_clock,
793        struct compat_timespec __user *tp)
794{
795    long err;
796    mm_segment_t oldfs;
797    struct timespec ts;
798
799    oldfs = get_fs();
800    set_fs(KERNEL_DS);
801    err = sys_clock_getres(which_clock,
802                   (struct timespec __user *) &ts);
803    set_fs(oldfs);
804    if (!err && tp && put_compat_timespec(&ts, tp))
805        return -EFAULT;
806    return err;
807}
808
809static long compat_clock_nanosleep_restart(struct restart_block *restart)
810{
811    long err;
812    mm_segment_t oldfs;
813    struct timespec tu;
814    struct compat_timespec *rmtp = restart->nanosleep.compat_rmtp;
815
816    restart->nanosleep.rmtp = (struct timespec __user *) &tu;
817    oldfs = get_fs();
818    set_fs(KERNEL_DS);
819    err = clock_nanosleep_restart(restart);
820    set_fs(oldfs);
821
822    if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
823        put_compat_timespec(&tu, rmtp))
824        return -EFAULT;
825
826    if (err == -ERESTART_RESTARTBLOCK) {
827        restart->fn = compat_clock_nanosleep_restart;
828        restart->nanosleep.compat_rmtp = rmtp;
829    }
830    return err;
831}
832
833long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
834                struct compat_timespec __user *rqtp,
835                struct compat_timespec __user *rmtp)
836{
837    long err;
838    mm_segment_t oldfs;
839    struct timespec in, out;
840    struct restart_block *restart;
841
842    if (get_compat_timespec(&in, rqtp))
843        return -EFAULT;
844
845    oldfs = get_fs();
846    set_fs(KERNEL_DS);
847    err = sys_clock_nanosleep(which_clock, flags,
848                  (struct timespec __user *) &in,
849                  (struct timespec __user *) &out);
850    set_fs(oldfs);
851
852    if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
853        put_compat_timespec(&out, rmtp))
854        return -EFAULT;
855
856    if (err == -ERESTART_RESTARTBLOCK) {
857        restart = &current_thread_info()->restart_block;
858        restart->fn = compat_clock_nanosleep_restart;
859        restart->nanosleep.compat_rmtp = rmtp;
860    }
861    return err;
862}
863
864/*
865 * We currently only need the following fields from the sigevent
866 * structure: sigev_value, sigev_signo, sig_notify and (sometimes
867 * sigev_notify_thread_id). The others are handled in user mode.
868 * We also assume that copying sigev_value.sival_int is sufficient
869 * to keep all the bits of sigev_value.sival_ptr intact.
870 */
871int get_compat_sigevent(struct sigevent *event,
872        const struct compat_sigevent __user *u_event)
873{
874    memset(event, 0, sizeof(*event));
875    return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) ||
876        __get_user(event->sigev_value.sival_int,
877            &u_event->sigev_value.sival_int) ||
878        __get_user(event->sigev_signo, &u_event->sigev_signo) ||
879        __get_user(event->sigev_notify, &u_event->sigev_notify) ||
880        __get_user(event->sigev_notify_thread_id,
881            &u_event->sigev_notify_thread_id))
882        ? -EFAULT : 0;
883}
884
885long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
886               unsigned long bitmap_size)
887{
888    int i, j;
889    unsigned long m;
890    compat_ulong_t um;
891    unsigned long nr_compat_longs;
892
893    /* align bitmap up to nearest compat_long_t boundary */
894    bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
895
896    if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
897        return -EFAULT;
898
899    nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
900
901    for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
902        m = 0;
903
904        for (j = 0; j < sizeof(m)/sizeof(um); j++) {
905            /*
906             * We dont want to read past the end of the userspace
907             * bitmap. We must however ensure the end of the
908             * kernel bitmap is zeroed.
909             */
910            if (nr_compat_longs-- > 0) {
911                if (__get_user(um, umask))
912                    return -EFAULT;
913            } else {
914                um = 0;
915            }
916
917            umask++;
918            m |= (long)um << (j * BITS_PER_COMPAT_LONG);
919        }
920        *mask++ = m;
921    }
922
923    return 0;
924}
925
926long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
927               unsigned long bitmap_size)
928{
929    int i, j;
930    unsigned long m;
931    compat_ulong_t um;
932    unsigned long nr_compat_longs;
933
934    /* align bitmap up to nearest compat_long_t boundary */
935    bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
936
937    if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
938        return -EFAULT;
939
940    nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
941
942    for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
943        m = *mask++;
944
945        for (j = 0; j < sizeof(m)/sizeof(um); j++) {
946            um = m;
947
948            /*
949             * We dont want to write past the end of the userspace
950             * bitmap.
951             */
952            if (nr_compat_longs-- > 0) {
953                if (__put_user(um, umask))
954                    return -EFAULT;
955            }
956
957            umask++;
958            m >>= 4*sizeof(um);
959            m >>= 4*sizeof(um);
960        }
961    }
962
963    return 0;
964}
965
966void
967sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
968{
969    switch (_NSIG_WORDS) {
970    case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
971    case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
972    case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
973    case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
974    }
975}
976EXPORT_SYMBOL_GPL(sigset_from_compat);
977
978asmlinkage long
979compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
980        struct compat_siginfo __user *uinfo,
981        struct compat_timespec __user *uts, compat_size_t sigsetsize)
982{
983    compat_sigset_t s32;
984    sigset_t s;
985    struct timespec t;
986    siginfo_t info;
987    long ret;
988
989    if (sigsetsize != sizeof(sigset_t))
990        return -EINVAL;
991
992    if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
993        return -EFAULT;
994    sigset_from_compat(&s, &s32);
995
996    if (uts) {
997        if (get_compat_timespec(&t, uts))
998            return -EFAULT;
999    }
1000
1001    ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
1002
1003    if (ret > 0 && uinfo) {
1004        if (copy_siginfo_to_user32(uinfo, &info))
1005            ret = -EFAULT;
1006    }
1007
1008    return ret;
1009
1010}
1011
1012asmlinkage long
1013compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig,
1014                 struct compat_siginfo __user *uinfo)
1015{
1016    siginfo_t info;
1017
1018    if (copy_siginfo_from_user32(&info, uinfo))
1019        return -EFAULT;
1020    return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
1021}
1022
1023#ifdef __ARCH_WANT_COMPAT_SYS_TIME
1024
1025/* compat_time_t is a 32 bit "long" and needs to get converted. */
1026
1027asmlinkage long compat_sys_time(compat_time_t __user * tloc)
1028{
1029    compat_time_t i;
1030    struct timeval tv;
1031
1032    do_gettimeofday(&tv);
1033    i = tv.tv_sec;
1034
1035    if (tloc) {
1036        if (put_user(i,tloc))
1037            return -EFAULT;
1038    }
1039    force_successful_syscall_return();
1040    return i;
1041}
1042
1043asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
1044{
1045    struct timespec tv;
1046    int err;
1047
1048    if (get_user(tv.tv_sec, tptr))
1049        return -EFAULT;
1050
1051    tv.tv_nsec = 0;
1052
1053    err = security_settime(&tv, NULL);
1054    if (err)
1055        return err;
1056
1057    do_settimeofday(&tv);
1058    return 0;
1059}
1060
1061#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
1062
1063#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
1064asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
1065{
1066    sigset_t newset;
1067    compat_sigset_t newset32;
1068
1069    /* XXX: Don't preclude handling different sized sigset_t's. */
1070    if (sigsetsize != sizeof(sigset_t))
1071        return -EINVAL;
1072
1073    if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
1074        return -EFAULT;
1075    sigset_from_compat(&newset, &newset32);
1076    return sigsuspend(&newset);
1077}
1078#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
1079
1080asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
1081{
1082    struct timex txc;
1083    int err, ret;
1084
1085    err = compat_get_timex(&txc, utp);
1086    if (err)
1087        return err;
1088
1089    ret = do_adjtimex(&txc);
1090
1091    err = compat_put_timex(utp, &txc);
1092    if (err)
1093        return err;
1094
1095    return ret;
1096}
1097
1098#ifdef CONFIG_NUMA
1099asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
1100        compat_uptr_t __user *pages32,
1101        const int __user *nodes,
1102        int __user *status,
1103        int flags)
1104{
1105    const void __user * __user *pages;
1106    int i;
1107
1108    pages = compat_alloc_user_space(nr_pages * sizeof(void *));
1109    for (i = 0; i < nr_pages; i++) {
1110        compat_uptr_t p;
1111
1112        if (get_user(p, pages32 + i) ||
1113            put_user(compat_ptr(p), pages + i))
1114            return -EFAULT;
1115    }
1116    return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
1117}
1118
1119asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
1120            compat_ulong_t maxnode,
1121            const compat_ulong_t __user *old_nodes,
1122            const compat_ulong_t __user *new_nodes)
1123{
1124    unsigned long __user *old = NULL;
1125    unsigned long __user *new = NULL;
1126    nodemask_t tmp_mask;
1127    unsigned long nr_bits;
1128    unsigned long size;
1129
1130    nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES);
1131    size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
1132    if (old_nodes) {
1133        if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits))
1134            return -EFAULT;
1135        old = compat_alloc_user_space(new_nodes ? size * 2 : size);
1136        if (new_nodes)
1137            new = old + size / sizeof(unsigned long);
1138        if (copy_to_user(old, nodes_addr(tmp_mask), size))
1139            return -EFAULT;
1140    }
1141    if (new_nodes) {
1142        if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits))
1143            return -EFAULT;
1144        if (new == NULL)
1145            new = compat_alloc_user_space(size);
1146        if (copy_to_user(new, nodes_addr(tmp_mask), size))
1147            return -EFAULT;
1148    }
1149    return sys_migrate_pages(pid, nr_bits + 1, old, new);
1150}
1151#endif
1152
1153struct compat_sysinfo {
1154    s32 uptime;
1155    u32 loads[3];
1156    u32 totalram;
1157    u32 freeram;
1158    u32 sharedram;
1159    u32 bufferram;
1160    u32 totalswap;
1161    u32 freeswap;
1162    u16 procs;
1163    u16 pad;
1164    u32 totalhigh;
1165    u32 freehigh;
1166    u32 mem_unit;
1167    char _f[20-2*sizeof(u32)-sizeof(int)];
1168};
1169
1170asmlinkage long
1171compat_sys_sysinfo(struct compat_sysinfo __user *info)
1172{
1173    struct sysinfo s;
1174
1175    do_sysinfo(&s);
1176
1177    /* Check to see if any memory value is too large for 32-bit and scale
1178     * down if needed
1179     */
1180    if ((s.totalram >> 32) || (s.totalswap >> 32)) {
1181        int bitcount = 0;
1182
1183        while (s.mem_unit < PAGE_SIZE) {
1184            s.mem_unit <<= 1;
1185            bitcount++;
1186        }
1187
1188        s.totalram >>= bitcount;
1189        s.freeram >>= bitcount;
1190        s.sharedram >>= bitcount;
1191        s.bufferram >>= bitcount;
1192        s.totalswap >>= bitcount;
1193        s.freeswap >>= bitcount;
1194        s.totalhigh >>= bitcount;
1195        s.freehigh >>= bitcount;
1196    }
1197
1198    if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) ||
1199        __put_user (s.uptime, &info->uptime) ||
1200        __put_user (s.loads[0], &info->loads[0]) ||
1201        __put_user (s.loads[1], &info->loads[1]) ||
1202        __put_user (s.loads[2], &info->loads[2]) ||
1203        __put_user (s.totalram, &info->totalram) ||
1204        __put_user (s.freeram, &info->freeram) ||
1205        __put_user (s.sharedram, &info->sharedram) ||
1206        __put_user (s.bufferram, &info->bufferram) ||
1207        __put_user (s.totalswap, &info->totalswap) ||
1208        __put_user (s.freeswap, &info->freeswap) ||
1209        __put_user (s.procs, &info->procs) ||
1210        __put_user (s.totalhigh, &info->totalhigh) ||
1211        __put_user (s.freehigh, &info->freehigh) ||
1212        __put_user (s.mem_unit, &info->mem_unit))
1213        return -EFAULT;
1214
1215    return 0;
1216}
1217
1218/*
1219 * Allocate user-space memory for the duration of a single system call,
1220 * in order to marshall parameters inside a compat thunk.
1221 */
1222void __user *compat_alloc_user_space(unsigned long len)
1223{
1224    void __user *ptr;
1225
1226    /* If len would occupy more than half of the entire compat space... */
1227    if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
1228        return NULL;
1229
1230    ptr = arch_compat_alloc_user_space(len);
1231
1232    if (unlikely(!access_ok(VERIFY_WRITE, ptr, len)))
1233        return NULL;
1234
1235    return ptr;
1236}
1237EXPORT_SYMBOL_GPL(compat_alloc_user_space);
1238

Archive Download this file



interactive