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