RHEL4/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/futex.h>        /* for FUTEX_WAIT */
  21#include <linux/syscalls.h>
  22#include <linux/unistd.h>
  23#include <linux/security.h>
  24
  25#include <asm/uaccess.h>
  26
  27int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
  28{
  29        return (verify_area(VERIFY_READ, cts, sizeof(*cts)) ||
  30                        __get_user(ts->tv_sec, &cts->tv_sec) ||
  31                        __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
  32}
  33
  34int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
  35{
  36        return (verify_area(VERIFY_WRITE, cts, sizeof(*cts)) ||
  37                        __put_user(ts->tv_sec, &cts->tv_sec) ||
  38                        __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
  39}
  40
  41static long compat_nanosleep_restart(struct restart_block *restart)
  42{
  43        unsigned long expire = restart->arg0, now = jiffies;
  44        struct compat_timespec __user *rmtp;
  45
  46        /* Did it expire while we handled signals? */
  47        if (!time_after(expire, now))
  48                return 0;
  49
  50        current->state = TASK_INTERRUPTIBLE;
  51        expire = schedule_timeout(expire - now);
  52        if (expire == 0)
  53                return 0;
  54
  55        rmtp = (struct compat_timespec __user *)restart->arg1;
  56        if (rmtp) {
  57                struct compat_timespec ct;
  58                struct timespec t;
  59
  60                jiffies_to_timespec(expire, &t);
  61                ct.tv_sec = t.tv_sec;
  62                ct.tv_nsec = t.tv_nsec;
  63                if (copy_to_user(rmtp, &ct, sizeof(ct)))
  64                        return -EFAULT;
  65        }
  66        /* The 'restart' block is already filled in */
  67        return -ERESTART_RESTARTBLOCK;
  68}
  69
  70asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
  71                struct compat_timespec __user *rmtp)
  72{
  73        struct timespec t;
  74        struct restart_block *restart;
  75        unsigned long expire;
  76
  77        if (get_compat_timespec(&t, rqtp))
  78                return -EFAULT;
  79
  80        if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0))
  81                return -EINVAL;
  82
  83        expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
  84        current->state = TASK_INTERRUPTIBLE;
  85        expire = schedule_timeout(expire);
  86        if (expire == 0)
  87                return 0;
  88
  89        if (rmtp) {
  90                jiffies_to_timespec(expire, &t);
  91                if (put_compat_timespec(&t, rmtp))
  92                        return -EFAULT;
  93        }
  94        restart = &current_thread_info()->restart_block;
  95        restart->fn = compat_nanosleep_restart;
  96        restart->arg0 = jiffies + expire;
  97        restart->arg1 = (unsigned long) rmtp;
  98        return -ERESTART_RESTARTBLOCK;
  99}
 100
 101static inline long get_compat_itimerval(struct itimerval *o,
 102                struct compat_itimerval __user *i)
 103{
 104        return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
 105                (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
 106                 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
 107                 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
 108                 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
 109}
 110
 111static inline long put_compat_itimerval(struct compat_itimerval __user *o,
 112                struct itimerval *i)
 113{
 114        return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
 115                (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
 116                 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
 117                 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
 118                 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
 119}
 120
 121asmlinkage long compat_sys_getitimer(int which,
 122                struct compat_itimerval __user *it)
 123{
 124        struct itimerval kit;
 125        int error;
 126
 127        error = do_getitimer(which, &kit);
 128        if (!error && put_compat_itimerval(it, &kit))
 129                error = -EFAULT;
 130        return error;
 131}
 132
 133asmlinkage long compat_sys_setitimer(int which,
 134                struct compat_itimerval __user *in,
 135                struct compat_itimerval __user *out)
 136{
 137        struct itimerval kin, kout;
 138        int error;
 139
 140        if (in) {
 141                if (get_compat_itimerval(&kin, in))
 142                        return -EFAULT;
 143        } else
 144                memset(&kin, 0, sizeof(kin));
 145
 146        error = do_setitimer(which, &kin, out ? &kout : NULL);
 147        if (error || !out)
 148                return error;
 149        if (put_compat_itimerval(out, &kout))
 150                return -EFAULT;
 151        return 0;
 152}
 153
 154asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
 155{
 156        /*
 157         *      In the SMP world we might just be unlucky and have one of
 158         *      the times increment as we use it. Since the value is an
 159         *      atomically safe type this is just fine. Conceptually its
 160         *      as if the syscall took an instant longer to occur.
 161         */
 162        if (tbuf) {
 163                struct compat_tms tmp;
 164                struct task_struct *tsk = current;
 165                struct task_struct *t;
 166                unsigned long utime, stime, cutime, cstime;
 167
 168                read_lock(&tasklist_lock);
 169                utime = tsk->signal->utime;
 170                stime = tsk->signal->stime;
 171                t = tsk;
 172                do {
 173                        utime += t->utime;
 174                        stime += t->stime;
 175                        t = next_thread(t);
 176                } while (t != tsk);
 177
 178                /*
 179                 * While we have tasklist_lock read-locked, no dying thread
 180                 * can be updating current->signal->[us]time.  Instead,
 181                 * we got their counts included in the live thread loop.
 182                 * However, another thread can come in right now and
 183                 * do a wait call that updates current->signal->c[us]time.
 184                 * To make sure we always see that pair updated atomically,
 185                 * we take the siglock around fetching them.
 186                 */
 187                spin_lock_irq(&tsk->sighand->siglock);
 188                cutime = tsk->signal->cutime;
 189                cstime = tsk->signal->cstime;
 190                spin_unlock_irq(&tsk->sighand->siglock);
 191                read_unlock(&tasklist_lock);
 192
 193                tmp.tms_utime = compat_jiffies_to_clock_t(utime);
 194                tmp.tms_stime = compat_jiffies_to_clock_t(stime);
 195                tmp.tms_cutime = compat_jiffies_to_clock_t(cutime);
 196                tmp.tms_cstime = compat_jiffies_to_clock_t(cstime);
 197                if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
 198                        return -EFAULT;
 199        }
 200        return compat_jiffies_to_clock_t(jiffies);
 201}
 202
 203/*
 204 * Assumption: old_sigset_t and compat_old_sigset_t are both
 205 * types that can be passed to put_user()/get_user().
 206 */
 207
 208asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
 209{
 210        old_sigset_t s;
 211        long ret;
 212        mm_segment_t old_fs = get_fs();
 213
 214        set_fs(KERNEL_DS);
 215        ret = sys_sigpending((old_sigset_t __user *) &s);
 216        set_fs(old_fs);
 217        if (ret == 0)
 218                ret = put_user(s, set);
 219        return ret;
 220}
 221
 222asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
 223                compat_old_sigset_t __user *oset)
 224{
 225        old_sigset_t s;
 226        long ret;
 227        mm_segment_t old_fs;
 228
 229        if (set && get_user(s, set))
 230                return -EFAULT;
 231        old_fs = get_fs();
 232        set_fs(KERNEL_DS);
 233        ret = sys_sigprocmask(how,
 234                              set ? (old_sigset_t __user *) &s : NULL,
 235                              oset ? (old_sigset_t __user *) &s : NULL);
 236        set_fs(old_fs);
 237        if (ret == 0)
 238                if (oset)
 239                        ret = put_user(s, oset);
 240        return ret;
 241}
 242
 243#ifdef CONFIG_FUTEX
 244asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, int val,
 245                struct compat_timespec __user *utime, u32 __user *uaddr2,
 246                int val3)
 247{
 248        struct timespec t;
 249        unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
 250        int val2 = 0;
 251
 252        if (utime && (op == FUTEX_WAIT)) {
 253                if (get_compat_timespec(&t, utime))
 254                        return -EFAULT;
 255                if ((t.tv_sec < 0) || (((unsigned) t.tv_nsec) >= NSEC_PER_SEC))
 256                        return -EINVAL;
 257                timeout = timespec_to_jiffies(&t) + 1;
 258        }
 259        if (op >= FUTEX_REQUEUE)
 260                val2 = (int) (unsigned long) utime;
 261
 262        return do_futex((unsigned long)uaddr, op, val, timeout,
 263                        (unsigned long)uaddr2, val2, val3);
 264}
 265#endif
 266
 267asmlinkage long compat_sys_setrlimit(unsigned int resource,
 268                struct compat_rlimit __user *rlim)
 269{
 270        struct rlimit r;
 271        int ret;
 272        mm_segment_t old_fs = get_fs ();
 273
 274        if (resource >= RLIM_NLIMITS) 
 275                return -EINVAL; 
 276
 277        if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
 278            __get_user(r.rlim_cur, &rlim->rlim_cur) ||
 279            __get_user(r.rlim_max, &rlim->rlim_max))
 280                return -EFAULT;
 281
 282        if (r.rlim_cur == COMPAT_RLIM_INFINITY)
 283                r.rlim_cur = RLIM_INFINITY;
 284        if (r.rlim_max == COMPAT_RLIM_INFINITY)
 285                r.rlim_max = RLIM_INFINITY;
 286        set_fs(KERNEL_DS);
 287        ret = sys_setrlimit(resource, (struct rlimit __user *) &r);
 288        set_fs(old_fs);
 289        return ret;
 290}
 291
 292#ifdef COMPAT_RLIM_OLD_INFINITY
 293
 294asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
 295                struct compat_rlimit __user *rlim)
 296{
 297        struct rlimit r;
 298        int ret;
 299        mm_segment_t old_fs = get_fs();
 300
 301        set_fs(KERNEL_DS);
 302        ret = sys_old_getrlimit(resource, &r);
 303        set_fs(old_fs);
 304
 305        if (!ret) {
 306                if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
 307                        r.rlim_cur = COMPAT_RLIM_INFINITY;
 308                if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
 309                        r.rlim_max = COMPAT_RLIM_INFINITY;
 310
 311                if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
 312                    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
 313                    __put_user(r.rlim_max, &rlim->rlim_max))
 314                        return -EFAULT;
 315        }
 316        return ret;
 317}
 318
 319#endif
 320
 321asmlinkage long compat_sys_getrlimit (unsigned int resource,
 322                struct compat_rlimit __user *rlim)
 323{
 324        struct rlimit r;
 325        int ret;
 326        mm_segment_t old_fs = get_fs();
 327
 328        set_fs(KERNEL_DS);
 329        ret = sys_getrlimit(resource, (struct rlimit __user *) &r);
 330        set_fs(old_fs);
 331        if (!ret) {
 332                if (r.rlim_cur > COMPAT_RLIM_INFINITY)
 333                        r.rlim_cur = COMPAT_RLIM_INFINITY;
 334                if (r.rlim_max > COMPAT_RLIM_INFINITY)
 335                        r.rlim_max = COMPAT_RLIM_INFINITY;
 336
 337                if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
 338                    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
 339                    __put_user(r.rlim_max, &rlim->rlim_max))
 340                        return -EFAULT;
 341        }
 342        return ret;
 343}
 344
 345int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
 346{
 347        if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
 348            __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
 349            __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
 350            __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
 351            __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
 352            __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
 353            __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
 354            __put_user(r->ru_idrss, &ru->ru_idrss) ||
 355            __put_user(r->ru_isrss, &ru->ru_isrss) ||
 356            __put_user(r->ru_minflt, &ru->ru_minflt) ||
 357            __put_user(r->ru_majflt, &ru->ru_majflt) ||
 358            __put_user(r->ru_nswap, &ru->ru_nswap) ||
 359            __put_user(r->ru_inblock, &ru->ru_inblock) ||
 360            __put_user(r->ru_oublock, &ru->ru_oublock) ||
 361            __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
 362            __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
 363            __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
 364            __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
 365            __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
 366                return -EFAULT;
 367        return 0;
 368}
 369
 370asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru)
 371{
 372        struct rusage r;
 373        int ret;
 374        mm_segment_t old_fs = get_fs();
 375
 376        set_fs(KERNEL_DS);
 377        ret = sys_getrusage(who, (struct rusage __user *) &r);
 378        set_fs(old_fs);
 379
 380        if (ret)
 381                return ret;
 382
 383        if (put_compat_rusage(&r, ru))
 384                return -EFAULT;
 385
 386        return 0;
 387}
 388
 389asmlinkage long
 390compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,
 391        struct compat_rusage __user *ru)
 392{
 393        if (!ru) {
 394                return sys_wait4(pid, stat_addr, options, NULL);
 395        } else {
 396                struct rusage r;
 397                int ret;
 398                unsigned int status;
 399                mm_segment_t old_fs = get_fs();
 400
 401                set_fs (KERNEL_DS);
 402                ret = sys_wait4(pid,
 403                                (stat_addr ?
 404                                 (unsigned int __user *) &status : NULL),
 405                                options, (struct rusage __user *) &r);
 406                set_fs (old_fs);
 407
 408                if (ret > 0) {
 409                        if (put_compat_rusage(&r, ru))
 410                                return -EFAULT;
 411                        if (stat_addr && put_user(status, stat_addr))
 412                                return -EFAULT;
 413                }
 414                return ret;
 415        }
 416}
 417
 418static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
 419                                    unsigned len, cpumask_t *new_mask)
 420{
 421        unsigned long *k;
 422
 423        if (len < sizeof(cpumask_t))
 424                memset(new_mask, 0, sizeof(cpumask_t));
 425        else if (len > sizeof(cpumask_t))
 426                len = sizeof(cpumask_t);
 427
 428        k = cpus_addr(*new_mask);
 429        return compat_get_bitmap(k, user_mask_ptr, len * 8);
 430}
 431
 432asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
 433                                             unsigned int len,
 434                                             compat_ulong_t __user *user_mask_ptr)
 435{
 436        cpumask_t new_mask;
 437        int retval;
 438
 439        retval = compat_get_user_cpu_mask(user_mask_ptr, len, &new_mask);
 440        if (retval)
 441                return retval;
 442
 443        return sched_setaffinity(pid, new_mask);
 444}
 445
 446asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
 447                                             compat_ulong_t __user *user_mask_ptr)
 448{
 449        int ret;
 450        cpumask_t mask;
 451        unsigned long *k;
 452        unsigned int min_length = sizeof(cpumask_t);
 453
 454        if (NR_CPUS <= BITS_PER_COMPAT_LONG)
 455                min_length = sizeof(compat_ulong_t);
 456
 457        if (len < min_length)
 458                return -EINVAL;
 459
 460        ret = sched_getaffinity(pid, &mask);
 461        if (ret < 0)
 462                return ret;
 463
 464        k = cpus_addr(mask);
 465        ret = compat_put_bitmap(user_mask_ptr, k, min_length * 8);
 466        if (ret)
 467                return ret;
 468
 469        return min_length;
 470}
 471
 472static int get_compat_itimerspec(struct itimerspec *dst, 
 473                                 struct compat_itimerspec __user *src)
 474{ 
 475        if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
 476            get_compat_timespec(&dst->it_value, &src->it_value))
 477                return -EFAULT;
 478        return 0;
 479} 
 480
 481static int put_compat_itimerspec(struct compat_itimerspec __user *dst, 
 482                                 struct itimerspec *src)
 483{ 
 484        if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
 485            put_compat_timespec(&src->it_value, &dst->it_value))
 486                return -EFAULT;
 487        return 0;
 488} 
 489
 490long compat_timer_settime(timer_t timer_id, int flags, 
 491                          struct compat_itimerspec __user *new, 
 492                          struct compat_itimerspec __user *old)
 493{ 
 494        long err;
 495        mm_segment_t oldfs;
 496        struct itimerspec newts, oldts;
 497
 498        if (!new)
 499                return -EINVAL;
 500        if (get_compat_itimerspec(&newts, new))
 501                return -EFAULT; 
 502        oldfs = get_fs();
 503        set_fs(KERNEL_DS);
 504        err = sys_timer_settime(timer_id, flags,
 505                                (struct itimerspec __user *) &newts,
 506                                (struct itimerspec __user *) &oldts);
 507        set_fs(oldfs); 
 508        if (!err && old && put_compat_itimerspec(old, &oldts))
 509                return -EFAULT;
 510        return err;
 511} 
 512
 513long compat_timer_gettime(timer_t timer_id,
 514                struct compat_itimerspec __user *setting)
 515{ 
 516        long err;
 517        mm_segment_t oldfs;
 518        struct itimerspec ts; 
 519
 520        oldfs = get_fs();
 521        set_fs(KERNEL_DS);
 522        err = sys_timer_gettime(timer_id,
 523                                (struct itimerspec __user *) &ts); 
 524        set_fs(oldfs); 
 525        if (!err && put_compat_itimerspec(setting, &ts))
 526                return -EFAULT;
 527        return err;
 528} 
 529
 530long compat_clock_settime(clockid_t which_clock,
 531                struct compat_timespec __user *tp)
 532{
 533        long err;
 534        mm_segment_t oldfs;
 535        struct timespec ts; 
 536
 537        if (get_compat_timespec(&ts, tp))
 538                return -EFAULT; 
 539        oldfs = get_fs();
 540        set_fs(KERNEL_DS);      
 541        err = sys_clock_settime(which_clock,
 542                                (struct timespec __user *) &ts);
 543        set_fs(oldfs);
 544        return err;
 545} 
 546
 547long compat_clock_gettime(clockid_t which_clock,
 548                struct compat_timespec __user *tp)
 549{
 550        long err;
 551        mm_segment_t oldfs;
 552        struct timespec ts; 
 553
 554        oldfs = get_fs();
 555        set_fs(KERNEL_DS);
 556        err = sys_clock_gettime(which_clock,
 557                                (struct timespec __user *) &ts);
 558        set_fs(oldfs);
 559        if (!err && put_compat_timespec(&ts, tp))
 560                return -EFAULT; 
 561        return err;
 562} 
 563
 564long compat_clock_getres(clockid_t which_clock,
 565                struct compat_timespec __user *tp)
 566{
 567        long err;
 568        mm_segment_t oldfs;
 569        struct timespec ts; 
 570
 571        oldfs = get_fs();
 572        set_fs(KERNEL_DS);
 573        err = sys_clock_getres(which_clock,
 574                               (struct timespec __user *) &ts);
 575        set_fs(oldfs);
 576        if (!err && tp && put_compat_timespec(&ts, tp))
 577                return -EFAULT; 
 578        return err;
 579} 
 580
 581long compat_clock_nanosleep(clockid_t which_clock, int flags,
 582                            struct compat_timespec __user *rqtp,
 583                            struct compat_timespec __user *rmtp)
 584{
 585        long err;
 586        mm_segment_t oldfs;
 587        struct timespec in, out; 
 588
 589        if (get_compat_timespec(&in, rqtp)) 
 590                return -EFAULT;
 591
 592        oldfs = get_fs();
 593        set_fs(KERNEL_DS);
 594        err = sys_clock_nanosleep(which_clock, flags,
 595                                  (struct timespec __user *) &in,
 596                                  (struct timespec __user *) &out);
 597        set_fs(oldfs);
 598        if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
 599            put_compat_timespec(&out, rmtp))
 600                return -EFAULT;
 601        return err;     
 602} 
 603
 604/* timer_create is architecture specific because it needs sigevent conversion */
 605
 606long compat_get_bitmap(unsigned long *mask, compat_ulong_t __user *umask,
 607                       unsigned long bitmap_size)
 608{
 609        int i, j;
 610        unsigned long m;
 611        compat_ulong_t um;
 612        unsigned long nr_compat_longs;
 613
 614        /* align bitmap up to nearest compat_long_t boundary */
 615        bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
 616
 617        if (verify_area(VERIFY_READ, umask, bitmap_size / 8))
 618                return -EFAULT;
 619
 620        nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
 621
 622        for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
 623                m = 0;
 624
 625                for (j = 0; j < sizeof(m)/sizeof(um); j++) {
 626                        /*
 627                         * We dont want to read past the end of the userspace
 628                         * bitmap. We must however ensure the end of the
 629                         * kernel bitmap is zeroed.
 630                         */
 631                        if (nr_compat_longs-- > 0) {
 632                                if (__get_user(um, umask))
 633                                        return -EFAULT;
 634                        } else {
 635                                um = 0;
 636                        }
 637
 638                        umask++;
 639                        m |= (long)um << (j * BITS_PER_COMPAT_LONG);
 640                }
 641                *mask++ = m;
 642        }
 643
 644        return 0;
 645}
 646
 647long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
 648                       unsigned long bitmap_size)
 649{
 650        int i, j;
 651        unsigned long m;
 652        compat_ulong_t um;
 653        unsigned long nr_compat_longs;
 654
 655        /* align bitmap up to nearest compat_long_t boundary */
 656        bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
 657
 658        if (verify_area(VERIFY_WRITE, umask, bitmap_size / 8))
 659                return -EFAULT;
 660
 661        nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
 662
 663        for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
 664                m = *mask++;
 665
 666                for (j = 0; j < sizeof(m)/sizeof(um); j++) {
 667                        um = m;
 668
 669                        /*
 670                         * We dont want to write past the end of the userspace
 671                         * bitmap.
 672                         */
 673                        if (nr_compat_longs-- > 0) {
 674                                if (__put_user(um, umask))
 675                                        return -EFAULT;
 676                        }
 677
 678                        umask++;
 679                        m >>= 4*sizeof(um);
 680                        m >>= 4*sizeof(um);
 681                }
 682        }
 683
 684        return 0;
 685}
 686
 687void
 688sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
 689{
 690        switch (_NSIG_WORDS) {
 691        case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
 692        case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
 693        case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
 694        case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
 695        }
 696}
 697
 698asmlinkage long
 699compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
 700                struct compat_siginfo __user *uinfo,
 701                struct compat_timespec __user *uts, compat_size_t sigsetsize)
 702{
 703        compat_sigset_t s32;
 704        sigset_t s;
 705        int sig;
 706        struct timespec t;
 707        siginfo_t info;
 708        long ret, timeout = 0;
 709
 710        if (sigsetsize != sizeof(sigset_t))
 711                return -EINVAL;
 712
 713        if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
 714                return -EFAULT;
 715        sigset_from_compat(&s, &s32);
 716        sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP));
 717        signotset(&s);
 718
 719        if (uts) {
 720                if (get_compat_timespec (&t, uts))
 721                        return -EFAULT;
 722                if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0
 723                                || t.tv_sec < 0)
 724                        return -EINVAL;
 725        }
 726
 727        spin_lock_irq(&current->sighand->siglock);
 728        sig = dequeue_signal(current, &s, &info);
 729        if (!sig) {
 730                timeout = MAX_SCHEDULE_TIMEOUT;
 731                if (uts)
 732                        timeout = timespec_to_jiffies(&t)
 733                                +(t.tv_sec || t.tv_nsec);
 734                if (timeout) {
 735                        current->real_blocked = current->blocked;
 736                        sigandsets(&current->blocked, &current->blocked, &s);
 737
 738                        recalc_sigpending();
 739                        spin_unlock_irq(&current->sighand->siglock);
 740
 741                        current->state = TASK_INTERRUPTIBLE;
 742                        timeout = schedule_timeout(timeout);
 743
 744                        spin_lock_irq(&current->sighand->siglock);
 745                        sig = dequeue_signal(current, &s, &info);
 746                        current->blocked = current->real_blocked;
 747                        siginitset(&current->real_blocked, 0);
 748                        recalc_sigpending();
 749                }
 750        }
 751        spin_unlock_irq(&current->sighand->siglock);
 752
 753        if (sig) {
 754                ret = sig;
 755                if (uinfo) {
 756                        if (copy_siginfo_to_user32(uinfo, &info))
 757                                ret = -EFAULT;
 758                }
 759        }else {
 760                ret = timeout?-EINTR:-EAGAIN;
 761        }
 762        return ret;
 763
 764}
 765
 766#ifdef __ARCH_WANT_COMPAT_SYS_TIME
 767
 768/* compat_time_t is a 32 bit "long" and needs to get converted. */
 769
 770asmlinkage long compat_sys_time(compat_time_t __user * tloc)
 771{
 772        compat_time_t i;
 773        struct timeval tv;
 774
 775        do_gettimeofday(&tv);
 776        i = tv.tv_sec;
 777
 778        if (tloc) {
 779                if (put_user(i,tloc))
 780                        i = -EFAULT;
 781        }
 782        return i;
 783}
 784
 785asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
 786{
 787        struct timespec tv;
 788
 789        if (!capable(CAP_SYS_TIME))
 790                return -EPERM;
 791        if (get_user(tv.tv_sec, tptr))
 792                return -EFAULT;
 793
 794        tv.tv_nsec = 0;
 795
 796        do_settimeofday(&tv);
 797        return 0;
 798}
 799
 800#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
 801