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