linux/fs/compat.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/compat.c
   3 *
   4 *  Kernel compatibililty routines for e.g. 32 bit syscall support
   5 *  on 64 bit kernels.
   6 *
   7 *  Copyright (C) 2002       Stephen Rothwell, IBM Corporation
   8 *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
   9 *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
  10 *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
  11 *  Copyright (C) 2003       Pavel Machek (pavel@suse.cz)
  12 *
  13 *  This program is free software; you can redistribute it and/or modify
  14 *  it under the terms of the GNU General Public License version 2 as
  15 *  published by the Free Software Foundation.
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/linkage.h>
  20#include <linux/compat.h>
  21#include <linux/errno.h>
  22#include <linux/time.h>
  23#include <linux/fs.h>
  24#include <linux/fcntl.h>
  25#include <linux/namei.h>
  26#include <linux/file.h>
  27#include <linux/fdtable.h>
  28#include <linux/vfs.h>
  29#include <linux/ioctl.h>
  30#include <linux/init.h>
  31#include <linux/smb.h>
  32#include <linux/smb_mount.h>
  33#include <linux/ncp_mount.h>
  34#include <linux/nfs4_mount.h>
  35#include <linux/smp_lock.h>
  36#include <linux/syscalls.h>
  37#include <linux/ctype.h>
  38#include <linux/module.h>
  39#include <linux/dirent.h>
  40#include <linux/fsnotify.h>
  41#include <linux/highuid.h>
  42#include <linux/sunrpc/svc.h>
  43#include <linux/nfsd/nfsd.h>
  44#include <linux/nfsd/syscall.h>
  45#include <linux/personality.h>
  46#include <linux/rwsem.h>
  47#include <linux/tsacct_kern.h>
  48#include <linux/security.h>
  49#include <linux/highmem.h>
  50#include <linux/signal.h>
  51#include <linux/poll.h>
  52#include <linux/mm.h>
  53#include <linux/eventpoll.h>
  54
  55#include <asm/uaccess.h>
  56#include <asm/mmu_context.h>
  57#include <asm/ioctls.h>
  58#include "internal.h"
  59
  60int compat_log = 1;
  61
  62int compat_printk(const char *fmt, ...)
  63{
  64        va_list ap;
  65        int ret;
  66        if (!compat_log)
  67                return 0;
  68        va_start(ap, fmt);
  69        ret = vprintk(fmt, ap);
  70        va_end(ap);
  71        return ret;
  72}
  73
  74#include "read_write.h"
  75
  76/*
  77 * Not all architectures have sys_utime, so implement this in terms
  78 * of sys_utimes.
  79 */
  80asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
  81{
  82        struct timespec tv[2];
  83
  84        if (t) {
  85                if (get_user(tv[0].tv_sec, &t->actime) ||
  86                    get_user(tv[1].tv_sec, &t->modtime))
  87                        return -EFAULT;
  88                tv[0].tv_nsec = 0;
  89                tv[1].tv_nsec = 0;
  90        }
  91        return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
  92}
  93
  94asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename, struct compat_timespec __user *t, int flags)
  95{
  96        struct timespec tv[2];
  97
  98        if  (t) {
  99                if (get_compat_timespec(&tv[0], &t[0]) ||
 100                    get_compat_timespec(&tv[1], &t[1]))
 101                        return -EFAULT;
 102
 103                if ((tv[0].tv_nsec == UTIME_OMIT || tv[0].tv_nsec == UTIME_NOW)
 104                    && tv[0].tv_sec != 0)
 105                        return -EINVAL;
 106                if ((tv[1].tv_nsec == UTIME_OMIT || tv[1].tv_nsec == UTIME_NOW)
 107                    && tv[1].tv_sec != 0)
 108                        return -EINVAL;
 109
 110                if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
 111                        return 0;
 112        }
 113        return do_utimes(dfd, filename, t ? tv : NULL, flags);
 114}
 115
 116asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, struct compat_timeval __user *t)
 117{
 118        struct timespec tv[2];
 119
 120        if (t) {
 121                if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
 122                    get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
 123                    get_user(tv[1].tv_sec, &t[1].tv_sec) ||
 124                    get_user(tv[1].tv_nsec, &t[1].tv_usec))
 125                        return -EFAULT;
 126                if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
 127                    tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
 128                        return -EINVAL;
 129                tv[0].tv_nsec *= 1000;
 130                tv[1].tv_nsec *= 1000;
 131        }
 132        return do_utimes(dfd, filename, t ? tv : NULL, 0);
 133}
 134
 135asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
 136{
 137        return compat_sys_futimesat(AT_FDCWD, filename, t);
 138}
 139
 140asmlinkage long compat_sys_newstat(char __user * filename,
 141                struct compat_stat __user *statbuf)
 142{
 143        struct kstat stat;
 144        int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
 145
 146        if (!error)
 147                error = cp_compat_stat(&stat, statbuf);
 148        return error;
 149}
 150
 151asmlinkage long compat_sys_newlstat(char __user * filename,
 152                struct compat_stat __user *statbuf)
 153{
 154        struct kstat stat;
 155        int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
 156
 157        if (!error)
 158                error = cp_compat_stat(&stat, statbuf);
 159        return error;
 160}
 161
 162#ifndef __ARCH_WANT_STAT64
 163asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user *filename,
 164                struct compat_stat __user *statbuf, int flag)
 165{
 166        struct kstat stat;
 167        int error = -EINVAL;
 168
 169        if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
 170                goto out;
 171
 172        if (flag & AT_SYMLINK_NOFOLLOW)
 173                error = vfs_lstat_fd(dfd, filename, &stat);
 174        else
 175                error = vfs_stat_fd(dfd, filename, &stat);
 176
 177        if (!error)
 178                error = cp_compat_stat(&stat, statbuf);
 179
 180out:
 181        return error;
 182}
 183#endif
 184
 185asmlinkage long compat_sys_newfstat(unsigned int fd,
 186                struct compat_stat __user * statbuf)
 187{
 188        struct kstat stat;
 189        int error = vfs_fstat(fd, &stat);
 190
 191        if (!error)
 192                error = cp_compat_stat(&stat, statbuf);
 193        return error;
 194}
 195
 196static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
 197{
 198        
 199        if (sizeof ubuf->f_blocks == 4) {
 200                if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
 201                     kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
 202                        return -EOVERFLOW;
 203                /* f_files and f_ffree may be -1; it's okay
 204                 * to stuff that into 32 bits */
 205                if (kbuf->f_files != 0xffffffffffffffffULL
 206                 && (kbuf->f_files & 0xffffffff00000000ULL))
 207                        return -EOVERFLOW;
 208                if (kbuf->f_ffree != 0xffffffffffffffffULL
 209                 && (kbuf->f_ffree & 0xffffffff00000000ULL))
 210                        return -EOVERFLOW;
 211        }
 212        if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 213            __put_user(kbuf->f_type, &ubuf->f_type) ||
 214            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 215            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
 216            __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
 217            __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
 218            __put_user(kbuf->f_files, &ubuf->f_files) ||
 219            __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
 220            __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 221            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 222            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 223            __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
 224            __put_user(0, &ubuf->f_spare[0]) || 
 225            __put_user(0, &ubuf->f_spare[1]) || 
 226            __put_user(0, &ubuf->f_spare[2]) || 
 227            __put_user(0, &ubuf->f_spare[3]) || 
 228            __put_user(0, &ubuf->f_spare[4]))
 229                return -EFAULT;
 230        return 0;
 231}
 232
 233/*
 234 * The following statfs calls are copies of code from fs/open.c and
 235 * should be checked against those from time to time
 236 */
 237asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
 238{
 239        struct path path;
 240        int error;
 241
 242        error = user_path(pathname, &path);
 243        if (!error) {
 244                struct kstatfs tmp;
 245                error = vfs_statfs(path.dentry, &tmp);
 246                if (!error)
 247                        error = put_compat_statfs(buf, &tmp);
 248                path_put(&path);
 249        }
 250        return error;
 251}
 252
 253asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
 254{
 255        struct file * file;
 256        struct kstatfs tmp;
 257        int error;
 258
 259        error = -EBADF;
 260        file = fget(fd);
 261        if (!file)
 262                goto out;
 263        error = vfs_statfs(file->f_path.dentry, &tmp);
 264        if (!error)
 265                error = put_compat_statfs(buf, &tmp);
 266        fput(file);
 267out:
 268        return error;
 269}
 270
 271static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
 272{
 273        if (sizeof ubuf->f_blocks == 4) {
 274                if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
 275                     kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
 276                        return -EOVERFLOW;
 277                /* f_files and f_ffree may be -1; it's okay
 278                 * to stuff that into 32 bits */
 279                if (kbuf->f_files != 0xffffffffffffffffULL
 280                 && (kbuf->f_files & 0xffffffff00000000ULL))
 281                        return -EOVERFLOW;
 282                if (kbuf->f_ffree != 0xffffffffffffffffULL
 283                 && (kbuf->f_ffree & 0xffffffff00000000ULL))
 284                        return -EOVERFLOW;
 285        }
 286        if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 287            __put_user(kbuf->f_type, &ubuf->f_type) ||
 288            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 289            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
 290            __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
 291            __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
 292            __put_user(kbuf->f_files, &ubuf->f_files) ||
 293            __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
 294            __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 295            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 296            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 297            __put_user(kbuf->f_frsize, &ubuf->f_frsize))
 298                return -EFAULT;
 299        return 0;
 300}
 301
 302asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
 303{
 304        struct path path;
 305        int error;
 306
 307        if (sz != sizeof(*buf))
 308                return -EINVAL;
 309
 310        error = user_path(pathname, &path);
 311        if (!error) {
 312                struct kstatfs tmp;
 313                error = vfs_statfs(path.dentry, &tmp);
 314                if (!error)
 315                        error = put_compat_statfs64(buf, &tmp);
 316                path_put(&path);
 317        }
 318        return error;
 319}
 320
 321asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
 322{
 323        struct file * file;
 324        struct kstatfs tmp;
 325        int error;
 326
 327        if (sz != sizeof(*buf))
 328                return -EINVAL;
 329
 330        error = -EBADF;
 331        file = fget(fd);
 332        if (!file)
 333                goto out;
 334        error = vfs_statfs(file->f_path.dentry, &tmp);
 335        if (!error)
 336                error = put_compat_statfs64(buf, &tmp);
 337        fput(file);
 338out:
 339        return error;
 340}
 341
 342static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 343{
 344        if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
 345            __get_user(kfl->l_type, &ufl->l_type) ||
 346            __get_user(kfl->l_whence, &ufl->l_whence) ||
 347            __get_user(kfl->l_start, &ufl->l_start) ||
 348            __get_user(kfl->l_len, &ufl->l_len) ||
 349            __get_user(kfl->l_pid, &ufl->l_pid))
 350                return -EFAULT;
 351        return 0;
 352}
 353
 354static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 355{
 356        if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
 357            __put_user(kfl->l_type, &ufl->l_type) ||
 358            __put_user(kfl->l_whence, &ufl->l_whence) ||
 359            __put_user(kfl->l_start, &ufl->l_start) ||
 360            __put_user(kfl->l_len, &ufl->l_len) ||
 361            __put_user(kfl->l_pid, &ufl->l_pid))
 362                return -EFAULT;
 363        return 0;
 364}
 365
 366#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
 367static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
 368{
 369        if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
 370            __get_user(kfl->l_type, &ufl->l_type) ||
 371            __get_user(kfl->l_whence, &ufl->l_whence) ||
 372            __get_user(kfl->l_start, &ufl->l_start) ||
 373            __get_user(kfl->l_len, &ufl->l_len) ||
 374            __get_user(kfl->l_pid, &ufl->l_pid))
 375                return -EFAULT;
 376        return 0;
 377}
 378#endif
 379
 380#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
 381static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
 382{
 383        if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
 384            __put_user(kfl->l_type, &ufl->l_type) ||
 385            __put_user(kfl->l_whence, &ufl->l_whence) ||
 386            __put_user(kfl->l_start, &ufl->l_start) ||
 387            __put_user(kfl->l_len, &ufl->l_len) ||
 388            __put_user(kfl->l_pid, &ufl->l_pid))
 389                return -EFAULT;
 390        return 0;
 391}
 392#endif
 393
 394asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
 395                unsigned long arg)
 396{
 397        mm_segment_t old_fs;
 398        struct flock f;
 399        long ret;
 400
 401        switch (cmd) {
 402        case F_GETLK:
 403        case F_SETLK:
 404        case F_SETLKW:
 405                ret = get_compat_flock(&f, compat_ptr(arg));
 406                if (ret != 0)
 407                        break;
 408                old_fs = get_fs();
 409                set_fs(KERNEL_DS);
 410                ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 411                set_fs(old_fs);
 412                if (cmd == F_GETLK && ret == 0) {
 413                        /* GETLK was successfule and we need to return the data...
 414                         * but it needs to fit in the compat structure.
 415                         * l_start shouldn't be too big, unless the original
 416                         * start + end is greater than COMPAT_OFF_T_MAX, in which
 417                         * case the app was asking for trouble, so we return
 418                         * -EOVERFLOW in that case.
 419                         * l_len could be too big, in which case we just truncate it,
 420                         * and only allow the app to see that part of the conflicting
 421                         * lock that might make sense to it anyway
 422                         */
 423
 424                        if (f.l_start > COMPAT_OFF_T_MAX)
 425                                ret = -EOVERFLOW;
 426                        if (f.l_len > COMPAT_OFF_T_MAX)
 427                                f.l_len = COMPAT_OFF_T_MAX;
 428                        if (ret == 0)
 429                                ret = put_compat_flock(&f, compat_ptr(arg));
 430                }
 431                break;
 432
 433        case F_GETLK64:
 434        case F_SETLK64:
 435        case F_SETLKW64:
 436                ret = get_compat_flock64(&f, compat_ptr(arg));
 437                if (ret != 0)
 438                        break;
 439                old_fs = get_fs();
 440                set_fs(KERNEL_DS);
 441                ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK :
 442                                ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW),
 443                                (unsigned long)&f);
 444                set_fs(old_fs);
 445                if (cmd == F_GETLK64 && ret == 0) {
 446                        /* need to return lock information - see above for commentary */
 447                        if (f.l_start > COMPAT_LOFF_T_MAX)
 448                                ret = -EOVERFLOW;
 449                        if (f.l_len > COMPAT_LOFF_T_MAX)
 450                                f.l_len = COMPAT_LOFF_T_MAX;
 451                        if (ret == 0)
 452                                ret = put_compat_flock64(&f, compat_ptr(arg));
 453                }
 454                break;
 455
 456        default:
 457                ret = sys_fcntl(fd, cmd, arg);
 458                break;
 459        }
 460        return ret;
 461}
 462
 463asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
 464                unsigned long arg)
 465{
 466        if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
 467                return -EINVAL;
 468        return compat_sys_fcntl64(fd, cmd, arg);
 469}
 470
 471asmlinkage long
 472compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
 473{
 474        long ret;
 475        aio_context_t ctx64;
 476
 477        mm_segment_t oldfs = get_fs();
 478        if (unlikely(get_user(ctx64, ctx32p)))
 479                return -EFAULT;
 480
 481        set_fs(KERNEL_DS);
 482        /* The __user pointer cast is valid because of the set_fs() */
 483        ret = sys_io_setup(nr_reqs, (aio_context_t __user *) &ctx64);
 484        set_fs(oldfs);
 485        /* truncating is ok because it's a user address */
 486        if (!ret)
 487                ret = put_user((u32) ctx64, ctx32p);
 488        return ret;
 489}
 490
 491asmlinkage long
 492compat_sys_io_getevents(aio_context_t ctx_id,
 493                                 unsigned long min_nr,
 494                                 unsigned long nr,
 495                                 struct io_event __user *events,
 496                                 struct compat_timespec __user *timeout)
 497{
 498        long ret;
 499        struct timespec t;
 500        struct timespec __user *ut = NULL;
 501
 502        ret = -EFAULT;
 503        if (unlikely(!access_ok(VERIFY_WRITE, events, 
 504                                nr * sizeof(struct io_event))))
 505                goto out;
 506        if (timeout) {
 507                if (get_compat_timespec(&t, timeout))
 508                        goto out;
 509
 510                ut = compat_alloc_user_space(sizeof(*ut));
 511                if (copy_to_user(ut, &t, sizeof(t)) )
 512                        goto out;
 513        } 
 514        ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
 515out:
 516        return ret;
 517}
 518
 519static inline long
 520copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
 521{
 522        compat_uptr_t uptr;
 523        int i;
 524
 525        for (i = 0; i < nr; ++i) {
 526                if (get_user(uptr, ptr32 + i))
 527                        return -EFAULT;
 528                if (put_user(compat_ptr(uptr), ptr64 + i))
 529                        return -EFAULT;
 530        }
 531        return 0;
 532}
 533
 534#define MAX_AIO_SUBMITS         (PAGE_SIZE/sizeof(struct iocb *))
 535
 536asmlinkage long
 537compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
 538{
 539        struct iocb __user * __user *iocb64; 
 540        long ret;
 541
 542        if (unlikely(nr < 0))
 543                return -EINVAL;
 544
 545        if (nr > MAX_AIO_SUBMITS)
 546                nr = MAX_AIO_SUBMITS;
 547        
 548        iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
 549        ret = copy_iocb(nr, iocb, iocb64);
 550        if (!ret)
 551                ret = sys_io_submit(ctx_id, nr, iocb64);
 552        return ret;
 553}
 554
 555struct compat_ncp_mount_data {
 556        compat_int_t version;
 557        compat_uint_t ncp_fd;
 558        __compat_uid_t mounted_uid;
 559        compat_pid_t wdog_pid;
 560        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
 561        compat_uint_t time_out;
 562        compat_uint_t retry_count;
 563        compat_uint_t flags;
 564        __compat_uid_t uid;
 565        __compat_gid_t gid;
 566        compat_mode_t file_mode;
 567        compat_mode_t dir_mode;
 568};
 569
 570struct compat_ncp_mount_data_v4 {
 571        compat_int_t version;
 572        compat_ulong_t flags;
 573        compat_ulong_t mounted_uid;
 574        compat_long_t wdog_pid;
 575        compat_uint_t ncp_fd;
 576        compat_uint_t time_out;
 577        compat_uint_t retry_count;
 578        compat_ulong_t uid;
 579        compat_ulong_t gid;
 580        compat_ulong_t file_mode;
 581        compat_ulong_t dir_mode;
 582};
 583
 584static void *do_ncp_super_data_conv(void *raw_data)
 585{
 586        int version = *(unsigned int *)raw_data;
 587
 588        if (version == 3) {
 589                struct compat_ncp_mount_data *c_n = raw_data;
 590                struct ncp_mount_data *n = raw_data;
 591
 592                n->dir_mode = c_n->dir_mode;
 593                n->file_mode = c_n->file_mode;
 594                n->gid = c_n->gid;
 595                n->uid = c_n->uid;
 596                memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
 597                n->wdog_pid = c_n->wdog_pid;
 598                n->mounted_uid = c_n->mounted_uid;
 599        } else if (version == 4) {
 600                struct compat_ncp_mount_data_v4 *c_n = raw_data;
 601                struct ncp_mount_data_v4 *n = raw_data;
 602
 603                n->dir_mode = c_n->dir_mode;
 604                n->file_mode = c_n->file_mode;
 605                n->gid = c_n->gid;
 606                n->uid = c_n->uid;
 607                n->retry_count = c_n->retry_count;
 608                n->time_out = c_n->time_out;
 609                n->ncp_fd = c_n->ncp_fd;
 610                n->wdog_pid = c_n->wdog_pid;
 611                n->mounted_uid = c_n->mounted_uid;
 612                n->flags = c_n->flags;
 613        } else if (version != 5) {
 614                return NULL;
 615        }
 616
 617        return raw_data;
 618}
 619
 620struct compat_smb_mount_data {
 621        compat_int_t version;
 622        __compat_uid_t mounted_uid;
 623        __compat_uid_t uid;
 624        __compat_gid_t gid;
 625        compat_mode_t file_mode;
 626        compat_mode_t dir_mode;
 627};
 628
 629static void *do_smb_super_data_conv(void *raw_data)
 630{
 631        struct smb_mount_data *s = raw_data;
 632        struct compat_smb_mount_data *c_s = raw_data;
 633
 634        if (c_s->version != SMB_MOUNT_OLDVERSION)
 635                goto out;
 636        s->dir_mode = c_s->dir_mode;
 637        s->file_mode = c_s->file_mode;
 638        s->gid = c_s->gid;
 639        s->uid = c_s->uid;
 640        s->mounted_uid = c_s->mounted_uid;
 641 out:
 642        return raw_data;
 643}
 644
 645struct compat_nfs_string {
 646        compat_uint_t len;
 647        compat_uptr_t data;
 648};
 649
 650static inline void compat_nfs_string(struct nfs_string *dst,
 651                                     struct compat_nfs_string *src)
 652{
 653        dst->data = compat_ptr(src->data);
 654        dst->len = src->len;
 655}
 656
 657struct compat_nfs4_mount_data_v1 {
 658        compat_int_t version;
 659        compat_int_t flags;
 660        compat_int_t rsize;
 661        compat_int_t wsize;
 662        compat_int_t timeo;
 663        compat_int_t retrans;
 664        compat_int_t acregmin;
 665        compat_int_t acregmax;
 666        compat_int_t acdirmin;
 667        compat_int_t acdirmax;
 668        struct compat_nfs_string client_addr;
 669        struct compat_nfs_string mnt_path;
 670        struct compat_nfs_string hostname;
 671        compat_uint_t host_addrlen;
 672        compat_uptr_t host_addr;
 673        compat_int_t proto;
 674        compat_int_t auth_flavourlen;
 675        compat_uptr_t auth_flavours;
 676};
 677
 678static int do_nfs4_super_data_conv(void *raw_data)
 679{
 680        int version = *(compat_uint_t *) raw_data;
 681
 682        if (version == 1) {
 683                struct compat_nfs4_mount_data_v1 *raw = raw_data;
 684                struct nfs4_mount_data *real = raw_data;
 685
 686                /* copy the fields backwards */
 687                real->auth_flavours = compat_ptr(raw->auth_flavours);
 688                real->auth_flavourlen = raw->auth_flavourlen;
 689                real->proto = raw->proto;
 690                real->host_addr = compat_ptr(raw->host_addr);
 691                real->host_addrlen = raw->host_addrlen;
 692                compat_nfs_string(&real->hostname, &raw->hostname);
 693                compat_nfs_string(&real->mnt_path, &raw->mnt_path);
 694                compat_nfs_string(&real->client_addr, &raw->client_addr);
 695                real->acdirmax = raw->acdirmax;
 696                real->acdirmin = raw->acdirmin;
 697                real->acregmax = raw->acregmax;
 698                real->acregmin = raw->acregmin;
 699                real->retrans = raw->retrans;
 700                real->timeo = raw->timeo;
 701                real->wsize = raw->wsize;
 702                real->rsize = raw->rsize;
 703                real->flags = raw->flags;
 704                real->version = raw->version;
 705        }
 706
 707        return 0;
 708}
 709
 710#define SMBFS_NAME      "smbfs"
 711#define NCPFS_NAME      "ncpfs"
 712#define NFS4_NAME       "nfs4"
 713
 714asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
 715                                 char __user * type, unsigned long flags,
 716                                 void __user * data)
 717{
 718        unsigned long type_page;
 719        unsigned long data_page;
 720        unsigned long dev_page;
 721        char *dir_page;
 722        int retval;
 723
 724        retval = copy_mount_options (type, &type_page);
 725        if (retval < 0)
 726                goto out;
 727
 728        dir_page = getname(dir_name);
 729        retval = PTR_ERR(dir_page);
 730        if (IS_ERR(dir_page))
 731                goto out1;
 732
 733        retval = copy_mount_options (dev_name, &dev_page);
 734        if (retval < 0)
 735                goto out2;
 736
 737        retval = copy_mount_options (data, &data_page);
 738        if (retval < 0)
 739                goto out3;
 740
 741        retval = -EINVAL;
 742
 743        if (type_page && data_page) {
 744                if (!strcmp((char *)type_page, SMBFS_NAME)) {
 745                        do_smb_super_data_conv((void *)data_page);
 746                } else if (!strcmp((char *)type_page, NCPFS_NAME)) {
 747                        do_ncp_super_data_conv((void *)data_page);
 748                } else if (!strcmp((char *)type_page, NFS4_NAME)) {
 749                        if (do_nfs4_super_data_conv((void *) data_page))
 750                                goto out4;
 751                }
 752        }
 753
 754        lock_kernel();
 755        retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
 756                        flags, (void*)data_page);
 757        unlock_kernel();
 758
 759 out4:
 760        free_page(data_page);
 761 out3:
 762        free_page(dev_page);
 763 out2:
 764        putname(dir_page);
 765 out1:
 766        free_page(type_page);
 767 out:
 768        return retval;
 769}
 770
 771#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
 772
 773struct compat_old_linux_dirent {
 774        compat_ulong_t  d_ino;
 775        compat_ulong_t  d_offset;
 776        unsigned short  d_namlen;
 777        char            d_name[1];
 778};
 779
 780struct compat_readdir_callback {
 781        struct compat_old_linux_dirent __user *dirent;
 782        int result;
 783};
 784
 785static int compat_fillonedir(void *__buf, const char *name, int namlen,
 786                        loff_t offset, u64 ino, unsigned int d_type)
 787{
 788        struct compat_readdir_callback *buf = __buf;
 789        struct compat_old_linux_dirent __user *dirent;
 790        compat_ulong_t d_ino;
 791
 792        if (buf->result)
 793                return -EINVAL;
 794        d_ino = ino;
 795        if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 796                buf->result = -EOVERFLOW;
 797                return -EOVERFLOW;
 798        }
 799        buf->result++;
 800        dirent = buf->dirent;
 801        if (!access_ok(VERIFY_WRITE, dirent,
 802                        (unsigned long)(dirent->d_name + namlen + 1) -
 803                                (unsigned long)dirent))
 804                goto efault;
 805        if (    __put_user(d_ino, &dirent->d_ino) ||
 806                __put_user(offset, &dirent->d_offset) ||
 807                __put_user(namlen, &dirent->d_namlen) ||
 808                __copy_to_user(dirent->d_name, name, namlen) ||
 809                __put_user(0, dirent->d_name + namlen))
 810                goto efault;
 811        return 0;
 812efault:
 813        buf->result = -EFAULT;
 814        return -EFAULT;
 815}
 816
 817asmlinkage long compat_sys_old_readdir(unsigned int fd,
 818        struct compat_old_linux_dirent __user *dirent, unsigned int count)
 819{
 820        int error;
 821        struct file *file;
 822        struct compat_readdir_callback buf;
 823
 824        error = -EBADF;
 825        file = fget(fd);
 826        if (!file)
 827                goto out;
 828
 829        buf.result = 0;
 830        buf.dirent = dirent;
 831
 832        error = vfs_readdir(file, compat_fillonedir, &buf);
 833        if (error >= 0)
 834                error = buf.result;
 835
 836        fput(file);
 837out:
 838        return error;
 839}
 840
 841struct compat_linux_dirent {
 842        compat_ulong_t  d_ino;
 843        compat_ulong_t  d_off;
 844        unsigned short  d_reclen;
 845        char            d_name[1];
 846};
 847
 848struct compat_getdents_callback {
 849        struct compat_linux_dirent __user *current_dir;
 850        struct compat_linux_dirent __user *previous;
 851        int count;
 852        int error;
 853};
 854
 855static int compat_filldir(void *__buf, const char *name, int namlen,
 856                loff_t offset, u64 ino, unsigned int d_type)
 857{
 858        struct compat_linux_dirent __user * dirent;
 859        struct compat_getdents_callback *buf = __buf;
 860        compat_ulong_t d_ino;
 861        int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(compat_long_t));
 862
 863        buf->error = -EINVAL;   /* only used if we fail.. */
 864        if (reclen > buf->count)
 865                return -EINVAL;
 866        d_ino = ino;
 867        if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
 868                buf->error = -EOVERFLOW;
 869                return -EOVERFLOW;
 870        }
 871        dirent = buf->previous;
 872        if (dirent) {
 873                if (__put_user(offset, &dirent->d_off))
 874                        goto efault;
 875        }
 876        dirent = buf->current_dir;
 877        if (__put_user(d_ino, &dirent->d_ino))
 878                goto efault;
 879        if (__put_user(reclen, &dirent->d_reclen))
 880                goto efault;
 881        if (copy_to_user(dirent->d_name, name, namlen))
 882                goto efault;
 883        if (__put_user(0, dirent->d_name + namlen))
 884                goto efault;
 885        if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
 886                goto efault;
 887        buf->previous = dirent;
 888        dirent = (void __user *)dirent + reclen;
 889        buf->current_dir = dirent;
 890        buf->count -= reclen;
 891        return 0;
 892efault:
 893        buf->error = -EFAULT;
 894        return -EFAULT;
 895}
 896
 897asmlinkage long compat_sys_getdents(unsigned int fd,
 898                struct compat_linux_dirent __user *dirent, unsigned int count)
 899{
 900        struct file * file;
 901        struct compat_linux_dirent __user * lastdirent;
 902        struct compat_getdents_callback buf;
 903        int error;
 904
 905        error = -EFAULT;
 906        if (!access_ok(VERIFY_WRITE, dirent, count))
 907                goto out;
 908
 909        error = -EBADF;
 910        file = fget(fd);
 911        if (!file)
 912                goto out;
 913
 914        buf.current_dir = dirent;
 915        buf.previous = NULL;
 916        buf.count = count;
 917        buf.error = 0;
 918
 919        error = vfs_readdir(file, compat_filldir, &buf);
 920        if (error < 0)
 921                goto out_putf;
 922        error = buf.error;
 923        lastdirent = buf.previous;
 924        if (lastdirent) {
 925                if (put_user(file->f_pos, &lastdirent->d_off))
 926                        error = -EFAULT;
 927                else
 928                        error = count - buf.count;
 929        }
 930
 931out_putf:
 932        fput(file);
 933out:
 934        return error;
 935}
 936
 937#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
 938
 939struct compat_getdents_callback64 {
 940        struct linux_dirent64 __user *current_dir;
 941        struct linux_dirent64 __user *previous;
 942        int count;
 943        int error;
 944};
 945
 946static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
 947                     u64 ino, unsigned int d_type)
 948{
 949        struct linux_dirent64 __user *dirent;
 950        struct compat_getdents_callback64 *buf = __buf;
 951        int jj = NAME_OFFSET(dirent);
 952        int reclen = ALIGN(jj + namlen + 1, sizeof(u64));
 953        u64 off;
 954
 955        buf->error = -EINVAL;   /* only used if we fail.. */
 956        if (reclen > buf->count)
 957                return -EINVAL;
 958        dirent = buf->previous;
 959
 960        if (dirent) {
 961                if (__put_user_unaligned(offset, &dirent->d_off))
 962                        goto efault;
 963        }
 964        dirent = buf->current_dir;
 965        if (__put_user_unaligned(ino, &dirent->d_ino))
 966                goto efault;
 967        off = 0;
 968        if (__put_user_unaligned(off, &dirent->d_off))
 969                goto efault;
 970        if (__put_user(reclen, &dirent->d_reclen))
 971                goto efault;
 972        if (__put_user(d_type, &dirent->d_type))
 973                goto efault;
 974        if (copy_to_user(dirent->d_name, name, namlen))
 975                goto efault;
 976        if (__put_user(0, dirent->d_name + namlen))
 977                goto efault;
 978        buf->previous = dirent;
 979        dirent = (void __user *)dirent + reclen;
 980        buf->current_dir = dirent;
 981        buf->count -= reclen;
 982        return 0;
 983efault:
 984        buf->error = -EFAULT;
 985        return -EFAULT;
 986}
 987
 988asmlinkage long compat_sys_getdents64(unsigned int fd,
 989                struct linux_dirent64 __user * dirent, unsigned int count)
 990{
 991        struct file * file;
 992        struct linux_dirent64 __user * lastdirent;
 993        struct compat_getdents_callback64 buf;
 994        int error;
 995
 996        error = -EFAULT;
 997        if (!access_ok(VERIFY_WRITE, dirent, count))
 998                goto out;
 999
1000        error = -EBADF;
1001        file = fget(fd);
1002        if (!file)
1003                goto out;
1004
1005        buf.current_dir = dirent;
1006        buf.previous = NULL;
1007        buf.count = count;
1008        buf.error = 0;
1009
1010        error = vfs_readdir(file, compat_filldir64, &buf);
1011        if (error < 0)
1012                goto out_putf;
1013        error = buf.error;
1014        lastdirent = buf.previous;
1015        if (lastdirent) {
1016                typeof(lastdirent->d_off) d_off = file->f_pos;
1017                error = -EFAULT;
1018                if (__put_user_unaligned(d_off, &lastdirent->d_off))
1019                        goto out_putf;
1020                error = count - buf.count;
1021        }
1022
1023out_putf:
1024        fput(file);
1025out:
1026        return error;
1027}
1028#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
1029
1030static ssize_t compat_do_readv_writev(int type, struct file *file,
1031                               const struct compat_iovec __user *uvector,
1032                               unsigned long nr_segs, loff_t *pos)
1033{
1034        compat_ssize_t tot_len;
1035        struct iovec iovstack[UIO_FASTIOV];
1036        struct iovec *iov=iovstack, *vector;
1037        ssize_t ret;
1038        int seg;
1039        io_fn_t fn;
1040        iov_fn_t fnv;
1041
1042        /*
1043         * SuS says "The readv() function *may* fail if the iovcnt argument
1044         * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
1045         * traditionally returned zero for zero segments, so...
1046         */
1047        ret = 0;
1048        if (nr_segs == 0)
1049                goto out;
1050
1051        /*
1052         * First get the "struct iovec" from user memory and
1053         * verify all the pointers
1054         */
1055        ret = -EINVAL;
1056        if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
1057                goto out;
1058        if (!file->f_op)
1059                goto out;
1060        if (nr_segs > UIO_FASTIOV) {
1061                ret = -ENOMEM;
1062                iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
1063                if (!iov)
1064                        goto out;
1065        }
1066        ret = -EFAULT;
1067        if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
1068                goto out;
1069
1070        /*
1071         * Single unix specification:
1072         * We should -EINVAL if an element length is not >= 0 and fitting an
1073         * ssize_t.  The total length is fitting an ssize_t
1074         *
1075         * Be careful here because iov_len is a size_t not an ssize_t
1076         */
1077        tot_len = 0;
1078        vector = iov;
1079        ret = -EINVAL;
1080        for (seg = 0 ; seg < nr_segs; seg++) {
1081                compat_ssize_t tmp = tot_len;
1082                compat_ssize_t len;
1083                compat_uptr_t buf;
1084
1085                if (__get_user(len, &uvector->iov_len) ||
1086                    __get_user(buf, &uvector->iov_base)) {
1087                        ret = -EFAULT;
1088                        goto out;
1089                }
1090                if (len < 0)    /* size_t not fitting an compat_ssize_t .. */
1091                        goto out;
1092                tot_len += len;
1093                if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
1094                        goto out;
1095                vector->iov_base = compat_ptr(buf);
1096                vector->iov_len = (compat_size_t) len;
1097                uvector++;
1098                vector++;
1099        }
1100        if (tot_len == 0) {
1101                ret = 0;
1102                goto out;
1103        }
1104
1105        ret = rw_verify_area(type, file, pos, tot_len);
1106        if (ret < 0)
1107                goto out;
1108
1109        fnv = NULL;
1110        if (type == READ) {
1111                fn = file->f_op->read;
1112                fnv = file->f_op->aio_read;
1113        } else {
1114                fn = (io_fn_t)file->f_op->write;
1115                fnv = file->f_op->aio_write;
1116        }
1117
1118        if (fnv)
1119                ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
1120                                                pos, fnv);
1121        else
1122                ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
1123
1124out:
1125        if (iov != iovstack)
1126                kfree(iov);
1127        if ((ret + (type == READ)) > 0) {
1128                struct dentry *dentry = file->f_path.dentry;
1129                if (type == READ)
1130                        fsnotify_access(dentry);
1131                else
1132                        fsnotify_modify(dentry);
1133        }
1134        return ret;
1135}
1136
1137asmlinkage ssize_t
1138compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1139{
1140        struct file *file;
1141        ssize_t ret = -EBADF;
1142
1143        file = fget(fd);
1144        if (!file)
1145                return -EBADF;
1146
1147        if (!(file->f_mode & FMODE_READ))
1148                goto out;
1149
1150        ret = -EINVAL;
1151        if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
1152                goto out;
1153
1154        ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
1155
1156out:
1157        fput(file);
1158        return ret;
1159}
1160
1161asmlinkage ssize_t
1162compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1163{
1164        struct file *file;
1165        ssize_t ret = -EBADF;
1166
1167        file = fget(fd);
1168        if (!file)
1169                return -EBADF;
1170        if (!(file->f_mode & FMODE_WRITE))
1171                goto out;
1172
1173        ret = -EINVAL;
1174        if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
1175                goto out;
1176
1177        ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
1178
1179out:
1180        fput(file);
1181        return ret;
1182}
1183
1184asmlinkage long
1185compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
1186                    unsigned int nr_segs, unsigned int flags)
1187{
1188        unsigned i;
1189        struct iovec __user *iov;
1190        if (nr_segs > UIO_MAXIOV)
1191                return -EINVAL;
1192        iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
1193        for (i = 0; i < nr_segs; i++) {
1194                struct compat_iovec v;
1195                if (get_user(v.iov_base, &iov32[i].iov_base) ||
1196                    get_user(v.iov_len, &iov32[i].iov_len) ||
1197                    put_user(compat_ptr(v.iov_base), &iov[i].iov_base) ||
1198                    put_user(v.iov_len, &iov[i].iov_len))
1199                        return -EFAULT;
1200        }
1201        return sys_vmsplice(fd, iov, nr_segs, flags);
1202}
1203
1204/*
1205 * Exactly like fs/open.c:sys_open(), except that it doesn't set the
1206 * O_LARGEFILE flag.
1207 */
1208asmlinkage long
1209compat_sys_open(const char __user *filename, int flags, int mode)
1210{
1211        return do_sys_open(AT_FDCWD, filename, flags, mode);
1212}
1213
1214/*
1215 * Exactly like fs/open.c:sys_openat(), except that it doesn't set the
1216 * O_LARGEFILE flag.
1217 */
1218asmlinkage long
1219compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int mode)
1220{
1221        return do_sys_open(dfd, filename, flags, mode);
1222}
1223
1224/*
1225 * compat_count() counts the number of arguments/envelopes. It is basically
1226 * a copy of count() from fs/exec.c, except that it works with 32 bit argv
1227 * and envp pointers.
1228 */
1229static int compat_count(compat_uptr_t __user *argv, int max)
1230{
1231        int i = 0;
1232
1233        if (argv != NULL) {
1234                for (;;) {
1235                        compat_uptr_t p;
1236
1237                        if (get_user(p, argv))
1238                                return -EFAULT;
1239                        if (!p)
1240                                break;
1241                        argv++;
1242                        if(++i > max)
1243                                return -E2BIG;
1244
1245                        if (fatal_signal_pending(current))
1246                                return -ERESTARTNOHAND;
1247                        cond_resched();
1248                }
1249        }
1250        return i;
1251}
1252
1253/*
1254 * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
1255 * except that it works with 32 bit argv and envp pointers.
1256 */
1257static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
1258                                struct linux_binprm *bprm)
1259{
1260        struct page *kmapped_page = NULL;
1261        char *kaddr = NULL;
1262        unsigned long kpos = 0;
1263        int ret;
1264
1265        while (argc-- > 0) {
1266                compat_uptr_t str;
1267                int len;
1268                unsigned long pos;
1269
1270                if (get_user(str, argv+argc) ||
1271                    !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
1272                        ret = -EFAULT;
1273                        goto out;
1274                }
1275
1276                if (len > MAX_ARG_STRLEN) {
1277                        ret = -E2BIG;
1278                        goto out;
1279                }
1280
1281                /* We're going to work our way backwords. */
1282                pos = bprm->p;
1283                str += len;
1284                bprm->p -= len;
1285
1286                while (len > 0) {
1287                        int offset, bytes_to_copy;
1288
1289                        if (fatal_signal_pending(current)) {
1290                                ret = -ERESTARTNOHAND;
1291                                goto out;
1292                        }
1293                        cond_resched();
1294
1295                        offset = pos % PAGE_SIZE;
1296                        if (offset == 0)
1297                                offset = PAGE_SIZE;
1298
1299                        bytes_to_copy = offset;
1300                        if (bytes_to_copy > len)
1301                                bytes_to_copy = len;
1302
1303                        offset -= bytes_to_copy;
1304                        pos -= bytes_to_copy;
1305                        str -= bytes_to_copy;
1306                        len -= bytes_to_copy;
1307
1308                        if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
1309                                struct page *page;
1310
1311                                page = get_arg_page(bprm, pos, 1);
1312                                if (!page) {
1313                                        ret = -E2BIG;
1314                                        goto out;
1315                                }
1316
1317                                if (kmapped_page) {
1318                                        flush_kernel_dcache_page(kmapped_page);
1319                                        kunmap(kmapped_page);
1320                                        put_page(kmapped_page);
1321                                }
1322                                kmapped_page = page;
1323                                kaddr = kmap(kmapped_page);
1324                                kpos = pos & PAGE_MASK;
1325                                flush_cache_page(bprm->vma, kpos,
1326                                                 page_to_pfn(kmapped_page));
1327                        }
1328                        if (copy_from_user(kaddr+offset, compat_ptr(str),
1329                                                bytes_to_copy)) {
1330                                ret = -EFAULT;
1331                                goto out;
1332                        }
1333                }
1334        }
1335        ret = 0;
1336out:
1337        if (kmapped_page) {
1338                flush_kernel_dcache_page(kmapped_page);
1339                kunmap(kmapped_page);
1340                put_page(kmapped_page);
1341        }
1342        return ret;
1343}
1344
1345/*
1346 * compat_do_execve() is mostly a copy of do_execve(), with the exception
1347 * that it processes 32 bit argv and envp pointers.
1348 */
1349int compat_do_execve(char * filename,
1350        compat_uptr_t __user *argv,
1351        compat_uptr_t __user *envp,
1352        struct pt_regs * regs)
1353{
1354        struct linux_binprm *bprm;
1355        struct file *file;
1356        struct files_struct *displaced;
1357        int retval;
1358
1359        retval = unshare_files(&displaced);
1360        if (retval)
1361                goto out_ret;
1362
1363        retval = -ENOMEM;
1364        bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1365        if (!bprm)
1366                goto out_files;
1367
1368        file = open_exec(filename);
1369        retval = PTR_ERR(file);
1370        if (IS_ERR(file))
1371                goto out_kfree;
1372
1373        sched_exec();
1374
1375        bprm->file = file;
1376        bprm->filename = filename;
1377        bprm->interp = filename;
1378
1379        retval = bprm_mm_init(bprm);
1380        if (retval)
1381                goto out_file;
1382
1383        bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
1384        if ((retval = bprm->argc) < 0)
1385                goto out_mm;
1386
1387        bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
1388        if ((retval = bprm->envc) < 0)
1389                goto out_mm;
1390
1391        retval = security_bprm_alloc(bprm);
1392        if (retval)
1393                goto out;
1394
1395        retval = prepare_binprm(bprm);
1396        if (retval < 0)
1397                goto out;
1398
1399        retval = copy_strings_kernel(1, &bprm->filename, bprm);
1400        if (retval < 0)
1401                goto out;
1402
1403        bprm->exec = bprm->p;
1404        retval = compat_copy_strings(bprm->envc, envp, bprm);
1405        if (retval < 0)
1406                goto out;
1407
1408        retval = compat_copy_strings(bprm->argc, argv, bprm);
1409        if (retval < 0)
1410                goto out;
1411
1412        retval = search_binary_handler(bprm, regs);
1413        if (retval >= 0) {
1414                /* execve success */
1415                security_bprm_free(bprm);
1416                acct_update_integrals(current);
1417                free_bprm(bprm);
1418                if (displaced)
1419                        put_files_struct(displaced);
1420                return retval;
1421        }
1422
1423out:
1424        if (bprm->security)
1425                security_bprm_free(bprm);
1426
1427out_mm:
1428        if (bprm->mm) {
1429                acct_arg_size(bprm, 0);
1430                mmput(bprm->mm);
1431        }
1432
1433out_file:
1434        if (bprm->file) {
1435                allow_write_access(bprm->file);
1436                fput(bprm->file);
1437        }
1438
1439out_kfree:
1440        free_bprm(bprm);
1441
1442out_files:
1443        if (displaced)
1444                reset_files_struct(displaced);
1445out_ret:
1446        return retval;
1447}
1448
1449#define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
1450
1451/*
1452 * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
1453 * 64-bit unsigned longs.
1454 */
1455static
1456int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1457                        unsigned long *fdset)
1458{
1459        nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
1460        if (ufdset) {
1461                unsigned long odd;
1462
1463                if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
1464                        return -EFAULT;
1465
1466                odd = nr & 1UL;
1467                nr &= ~1UL;
1468                while (nr) {
1469                        unsigned long h, l;
1470                        if (__get_user(l, ufdset) || __get_user(h, ufdset+1))
1471                                return -EFAULT;
1472                        ufdset += 2;
1473                        *fdset++ = h << 32 | l;
1474                        nr -= 2;
1475                }
1476                if (odd && __get_user(*fdset, ufdset))
1477                        return -EFAULT;
1478        } else {
1479                /* Tricky, must clear full unsigned long in the
1480                 * kernel fdset at the end, this makes sure that
1481                 * actually happens.
1482                 */
1483                memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
1484        }
1485        return 0;
1486}
1487
1488static
1489int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1490                      unsigned long *fdset)
1491{
1492        unsigned long odd;
1493        nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
1494
1495        if (!ufdset)
1496                return 0;
1497
1498        odd = nr & 1UL;
1499        nr &= ~1UL;
1500        while (nr) {
1501                unsigned long h, l;
1502                l = *fdset++;
1503                h = l >> 32;
1504                if (__put_user(l, ufdset) || __put_user(h, ufdset+1))
1505                        return -EFAULT;
1506                ufdset += 2;
1507                nr -= 2;
1508        }
1509        if (odd && __put_user(*fdset, ufdset))
1510                return -EFAULT;
1511        return 0;
1512}
1513
1514
1515/*
1516 * This is a virtual copy of sys_select from fs/select.c and probably
1517 * should be compared to it from time to time
1518 */
1519
1520/*
1521 * We can actually return ERESTARTSYS instead of EINTR, but I'd
1522 * like to be certain this leads to no problems. So I return
1523 * EINTR just for safety.
1524 *
1525 * Update: ERESTARTSYS breaks at least the xview clock binary, so
1526 * I'm trying ERESTARTNOHAND which restart only when you want to.
1527 */
1528#define MAX_SELECT_SECONDS \
1529        ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
1530
1531int compat_core_sys_select(int n, compat_ulong_t __user *inp,
1532        compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout)
1533{
1534        fd_set_bits fds;
1535        void *bits;
1536        int size, max_fds, ret = -EINVAL;
1537        struct fdtable *fdt;
1538        long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
1539
1540        if (n < 0)
1541                goto out_nofds;
1542
1543        /* max_fds can increase, so grab it once to avoid race */
1544        rcu_read_lock();
1545        fdt = files_fdtable(current->files);
1546        max_fds = fdt->max_fds;
1547        rcu_read_unlock();
1548        if (n > max_fds)
1549                n = max_fds;
1550
1551        /*
1552         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
1553         * since we used fdset we need to allocate memory in units of
1554         * long-words.
1555         */
1556        size = FDS_BYTES(n);
1557        bits = stack_fds;
1558        if (size > sizeof(stack_fds) / 6) {
1559                bits = kmalloc(6 * size, GFP_KERNEL);
1560                ret = -ENOMEM;
1561                if (!bits)
1562                        goto out_nofds;
1563        }
1564        fds.in      = (unsigned long *)  bits;
1565        fds.out     = (unsigned long *) (bits +   size);
1566        fds.ex      = (unsigned long *) (bits + 2*size);
1567        fds.res_in  = (unsigned long *) (bits + 3*size);
1568        fds.res_out = (unsigned long *) (bits + 4*size);
1569        fds.res_ex  = (unsigned long *) (bits + 5*size);
1570
1571        if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
1572            (ret = compat_get_fd_set(n, outp, fds.out)) ||
1573            (ret = compat_get_fd_set(n, exp, fds.ex)))
1574                goto out;
1575        zero_fd_set(n, fds.res_in);
1576        zero_fd_set(n, fds.res_out);
1577        zero_fd_set(n, fds.res_ex);
1578
1579        ret = do_select(n, &fds, timeout);
1580
1581        if (ret < 0)
1582                goto out;
1583        if (!ret) {
1584                ret = -ERESTARTNOHAND;
1585                if (signal_pending(current))
1586                        goto out;
1587                ret = 0;
1588        }
1589
1590        if (compat_set_fd_set(n, inp, fds.res_in) ||
1591            compat_set_fd_set(n, outp, fds.res_out) ||
1592            compat_set_fd_set(n, exp, fds.res_ex))
1593                ret = -EFAULT;
1594out:
1595        if (bits != stack_fds)
1596                kfree(bits);
1597out_nofds:
1598        return ret;
1599}
1600
1601asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
1602        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
1603        struct compat_timeval __user *tvp)
1604{
1605        s64 timeout = -1;
1606        struct compat_timeval tv;
1607        int ret;
1608
1609        if (tvp) {
1610                if (copy_from_user(&tv, tvp, sizeof(tv)))
1611                        return -EFAULT;
1612
1613                if (tv.tv_sec < 0 || tv.tv_usec < 0)
1614                        return -EINVAL;
1615
1616                /* Cast to u64 to make GCC stop complaining */
1617                if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
1618                        timeout = -1;   /* infinite */
1619                else {
1620                        timeout = DIV_ROUND_UP(tv.tv_usec, 1000000/HZ);
1621                        timeout += tv.tv_sec * HZ;
1622                }
1623        }
1624
1625        ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
1626
1627        if (tvp) {
1628                struct compat_timeval rtv;
1629
1630                if (current->personality & STICKY_TIMEOUTS)
1631                        goto sticky;
1632                rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ));
1633                rtv.tv_sec = timeout;
1634                if (compat_timeval_compare(&rtv, &tv) >= 0)
1635                        rtv = tv;
1636                if (copy_to_user(tvp, &rtv, sizeof(rtv))) {
1637sticky:
1638                        /*
1639                         * If an application puts its timeval in read-only
1640                         * memory, we don't want the Linux-specific update to
1641                         * the timeval to cause a fault after the select has
1642                         * completed successfully. However, because we're not
1643                         * updating the timeval, we can't restart the system
1644                         * call.
1645                         */
1646                        if (ret == -ERESTARTNOHAND)
1647                                ret = -EINTR;
1648                }
1649        }
1650
1651        return ret;
1652}
1653
1654#ifdef HAVE_SET_RESTORE_SIGMASK
1655static long do_compat_pselect(int n, compat_ulong_t __user *inp,
1656        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
1657        struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
1658        compat_size_t sigsetsize)
1659{
1660        compat_sigset_t ss32;
1661        sigset_t ksigmask, sigsaved;
1662        s64 timeout = MAX_SCHEDULE_TIMEOUT;
1663        struct compat_timespec ts;
1664        int ret;
1665
1666        if (tsp) {
1667                if (copy_from_user(&ts, tsp, sizeof(ts)))
1668                        return -EFAULT;
1669
1670                if (ts.tv_sec < 0 || ts.tv_nsec < 0)
1671                        return -EINVAL;
1672        }
1673
1674        if (sigmask) {
1675                if (sigsetsize != sizeof(compat_sigset_t))
1676                        return -EINVAL;
1677                if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
1678                        return -EFAULT;
1679                sigset_from_compat(&ksigmask, &ss32);
1680
1681                sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
1682                sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
1683        }
1684
1685        do {
1686                if (tsp) {
1687                        if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
1688                                timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
1689                                timeout += ts.tv_sec * (unsigned long)HZ;
1690                                ts.tv_sec = 0;
1691                                ts.tv_nsec = 0;
1692                        } else {
1693                                ts.tv_sec -= MAX_SELECT_SECONDS;
1694                                timeout = MAX_SELECT_SECONDS * HZ;
1695                        }
1696                }
1697
1698                ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
1699
1700        } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec));
1701
1702        if (tsp) {
1703                struct compat_timespec rts;
1704
1705                if (current->personality & STICKY_TIMEOUTS)
1706                        goto sticky;
1707
1708                rts.tv_sec = timeout / HZ;
1709                rts.tv_nsec = (timeout % HZ) * (NSEC_PER_SEC/HZ);
1710                if (rts.tv_nsec >= NSEC_PER_SEC) {
1711                        rts.tv_sec++;
1712                        rts.tv_nsec -= NSEC_PER_SEC;
1713                }
1714                if (compat_timespec_compare(&rts, &ts) >= 0)
1715                        rts = ts;
1716                if (copy_to_user(tsp, &rts, sizeof(rts))) {
1717sticky:
1718                        /*
1719                         * If an application puts its timeval in read-only
1720                         * memory, we don't want the Linux-specific update to
1721                         * the timeval to cause a fault after the select has
1722                         * completed successfully. However, because we're not
1723                         * updating the timeval, we can't restart the system
1724                         * call.
1725                         */
1726                        if (ret == -ERESTARTNOHAND)
1727                                ret = -EINTR;
1728                }
1729        }
1730
1731        if (ret == -ERESTARTNOHAND) {
1732                /*
1733                 * Don't restore the signal mask yet. Let do_signal() deliver
1734                 * the signal on the way back to userspace, before the signal
1735                 * mask is restored.
1736                 */
1737                if (sigmask) {
1738                        memcpy(&current->saved_sigmask, &sigsaved,
1739                                        sizeof(sigsaved));
1740                        set_restore_sigmask();
1741                }
1742        } else if (sigmask)
1743                sigprocmask(SIG_SETMASK, &sigsaved, NULL);
1744
1745        return ret;
1746}
1747
1748asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
1749        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
1750        struct compat_timespec __user *tsp, void __user *sig)
1751{
1752        compat_size_t sigsetsize = 0;
1753        compat_uptr_t up = 0;
1754
1755        if (sig) {
1756                if (!access_ok(VERIFY_READ, sig,
1757                                sizeof(compat_uptr_t)+sizeof(compat_size_t)) ||
1758                        __get_user(up, (compat_uptr_t __user *)sig) ||
1759                        __get_user(sigsetsize,
1760                                (compat_size_t __user *)(sig+sizeof(up))))
1761                        return -EFAULT;
1762        }
1763        return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(up),
1764                                 sigsetsize);
1765}
1766
1767asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
1768        unsigned int nfds, struct compat_timespec __user *tsp,
1769        const compat_sigset_t __user *sigmask, compat_size_t sigsetsize)
1770{
1771        compat_sigset_t ss32;
1772        sigset_t ksigmask, sigsaved;
1773        struct compat_timespec ts;
1774        s64 timeout = -1;
1775        int ret;
1776
1777        if (tsp) {
1778                if (copy_from_user(&ts, tsp, sizeof(ts)))
1779                        return -EFAULT;
1780
1781                /* We assume that ts.tv_sec is always lower than
1782                   the number of seconds that can be expressed in
1783                   an s64. Otherwise the compiler bitches at us */
1784                timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
1785                timeout += ts.tv_sec * HZ;
1786        }
1787
1788        if (sigmask) {
1789                if (sigsetsize != sizeof(compat_sigset_t))
1790                        return -EINVAL;
1791                if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
1792                        return -EFAULT;
1793                sigset_from_compat(&ksigmask, &ss32);
1794
1795                sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
1796                sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
1797        }
1798
1799        ret = do_sys_poll(ufds, nfds, &timeout);
1800
1801        /* We can restart this syscall, usually */
1802        if (ret == -EINTR) {
1803                /*
1804                 * Don't restore the signal mask yet. Let do_signal() deliver
1805                 * the signal on the way back to userspace, before the signal
1806                 * mask is restored.
1807                 */
1808                if (sigmask) {
1809                        memcpy(&current->saved_sigmask, &sigsaved,
1810                                sizeof(sigsaved));
1811                        set_restore_sigmask();
1812                }
1813                ret = -ERESTARTNOHAND;
1814        } else if (sigmask)
1815                sigprocmask(SIG_SETMASK, &sigsaved, NULL);
1816
1817        if (tsp && timeout >= 0) {
1818                struct compat_timespec rts;
1819
1820                if (current->personality & STICKY_TIMEOUTS)
1821                        goto sticky;
1822                /* Yes, we know it's actually an s64, but it's also positive. */
1823                rts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) *
1824                                        1000;
1825                rts.tv_sec = timeout;
1826                if (compat_timespec_compare(&rts, &ts) >= 0)
1827                        rts = ts;
1828                if (copy_to_user(tsp, &rts, sizeof(rts))) {
1829sticky:
1830                        /*
1831                         * If an application puts its timeval in read-only
1832                         * memory, we don't want the Linux-specific update to
1833                         * the timeval to cause a fault after the select has
1834                         * completed successfully. However, because we're not
1835                         * updating the timeval, we can't restart the system
1836                         * call.
1837                         */
1838                        if (ret == -ERESTARTNOHAND && timeout >= 0)
1839                                ret = -EINTR;
1840                }
1841        }
1842
1843        return ret;
1844}
1845#endif /* HAVE_SET_RESTORE_SIGMASK */
1846
1847#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
1848/* Stuff for NFS server syscalls... */
1849struct compat_nfsctl_svc {
1850        u16                     svc32_port;
1851        s32                     svc32_nthreads;
1852};
1853
1854struct compat_nfsctl_client {
1855        s8                      cl32_ident[NFSCLNT_IDMAX+1];
1856        s32                     cl32_naddr;
1857        struct in_addr          cl32_addrlist[NFSCLNT_ADDRMAX];
1858        s32                     cl32_fhkeytype;
1859        s32                     cl32_fhkeylen;
1860        u8                      cl32_fhkey[NFSCLNT_KEYMAX];
1861};
1862
1863struct compat_nfsctl_export {
1864        char            ex32_client[NFSCLNT_IDMAX+1];
1865        char            ex32_path[NFS_MAXPATHLEN+1];
1866        compat_dev_t    ex32_dev;
1867        compat_ino_t    ex32_ino;
1868        compat_int_t    ex32_flags;
1869        __compat_uid_t  ex32_anon_uid;
1870        __compat_gid_t  ex32_anon_gid;
1871};
1872
1873struct compat_nfsctl_fdparm {
1874        struct sockaddr         gd32_addr;
1875        s8                      gd32_path[NFS_MAXPATHLEN+1];
1876        compat_int_t            gd32_version;
1877};
1878
1879struct compat_nfsctl_fsparm {
1880        struct sockaddr         gd32_addr;
1881        s8                      gd32_path[NFS_MAXPATHLEN+1];
1882        compat_int_t            gd32_maxlen;
1883};
1884
1885struct compat_nfsctl_arg {
1886        compat_int_t            ca32_version;   /* safeguard */
1887        union {
1888                struct compat_nfsctl_svc        u32_svc;
1889                struct compat_nfsctl_client     u32_client;
1890                struct compat_nfsctl_export     u32_export;
1891                struct compat_nfsctl_fdparm     u32_getfd;
1892                struct compat_nfsctl_fsparm     u32_getfs;
1893        } u;
1894#define ca32_svc        u.u32_svc
1895#define ca32_client     u.u32_client
1896#define ca32_export     u.u32_export
1897#define ca32_getfd      u.u32_getfd
1898#define ca32_getfs      u.u32_getfs
1899};
1900
1901union compat_nfsctl_res {
1902        __u8                    cr32_getfh[NFS_FHSIZE];
1903        struct knfsd_fh         cr32_getfs;
1904};
1905
1906static int compat_nfs_svc_trans(struct nfsctl_arg *karg,
1907                                struct compat_nfsctl_arg __user *arg)
1908{
1909        if (!access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc)) ||
1910                get_user(karg->ca_version, &arg->ca32_version) ||
1911                __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port) ||
1912                __get_user(karg->ca_svc.svc_nthreads,
1913                                &arg->ca32_svc.svc32_nthreads))
1914                return -EFAULT;
1915        return 0;
1916}
1917
1918static int compat_nfs_clnt_trans(struct nfsctl_arg *karg,
1919                                struct compat_nfsctl_arg __user *arg)
1920{
1921        if (!access_ok(VERIFY_READ, &arg->ca32_client,
1922                        sizeof(arg->ca32_client)) ||
1923                get_user(karg->ca_version, &arg->ca32_version) ||
1924                __copy_from_user(&karg->ca_client.cl_ident[0],
1925                                &arg->ca32_client.cl32_ident[0],
1926                                NFSCLNT_IDMAX) ||
1927                __get_user(karg->ca_client.cl_naddr,
1928                                &arg->ca32_client.cl32_naddr) ||
1929                __copy_from_user(&karg->ca_client.cl_addrlist[0],
1930                                &arg->ca32_client.cl32_addrlist[0],
1931                                (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)) ||
1932                __get_user(karg->ca_client.cl_fhkeytype,
1933                                &arg->ca32_client.cl32_fhkeytype) ||
1934                __get_user(karg->ca_client.cl_fhkeylen,
1935                                &arg->ca32_client.cl32_fhkeylen) ||
1936                __copy_from_user(&karg->ca_client.cl_fhkey[0],
1937                                &arg->ca32_client.cl32_fhkey[0],
1938                                NFSCLNT_KEYMAX))
1939                return -EFAULT;
1940
1941        return 0;
1942}
1943
1944static int compat_nfs_exp_trans(struct nfsctl_arg *karg,
1945                                struct compat_nfsctl_arg __user *arg)
1946{
1947        if (!access_ok(VERIFY_READ, &arg->ca32_export,
1948                                sizeof(arg->ca32_export)) ||
1949                get_user(karg->ca_version, &arg->ca32_version) ||
1950                __copy_from_user(&karg->ca_export.ex_client[0],
1951                                &arg->ca32_export.ex32_client[0],
1952                                NFSCLNT_IDMAX) ||
1953                __copy_from_user(&karg->ca_export.ex_path[0],
1954                                &arg->ca32_export.ex32_path[0],
1955                                NFS_MAXPATHLEN) ||
1956                __get_user(karg->ca_export.ex_dev,
1957                                &arg->ca32_export.ex32_dev) ||
1958                __get_user(karg->ca_export.ex_ino,
1959                                &arg->ca32_export.ex32_ino) ||
1960                __get_user(karg->ca_export.ex_flags,
1961                                &arg->ca32_export.ex32_flags) ||
1962                __get_user(karg->ca_export.ex_anon_uid,
1963                                &arg->ca32_export.ex32_anon_uid) ||
1964                __get_user(karg->ca_export.ex_anon_gid,
1965                                &arg->ca32_export.ex32_anon_gid))
1966                return -EFAULT;
1967        SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
1968        SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
1969
1970        return 0;
1971}
1972
1973static int compat_nfs_getfd_trans(struct nfsctl_arg *karg,
1974                                struct compat_nfsctl_arg __user *arg)
1975{
1976        if (!access_ok(VERIFY_READ, &arg->ca32_getfd,
1977                        sizeof(arg->ca32_getfd)) ||
1978                get_user(karg->ca_version, &arg->ca32_version) ||
1979                __copy_from_user(&karg->ca_getfd.gd_addr,
1980                                &arg->ca32_getfd.gd32_addr,
1981                                (sizeof(struct sockaddr))) ||
1982                __copy_from_user(&karg->ca_getfd.gd_path,
1983                                &arg->ca32_getfd.gd32_path,
1984                                (NFS_MAXPATHLEN+1)) ||
1985                __get_user(karg->ca_getfd.gd_version,
1986                                &arg->ca32_getfd.gd32_version))
1987                return -EFAULT;
1988
1989        return 0;
1990}
1991
1992static int compat_nfs_getfs_trans(struct nfsctl_arg *karg,
1993                                struct compat_nfsctl_arg __user *arg)
1994{
1995        if (!access_ok(VERIFY_READ,&arg->ca32_getfs,sizeof(arg->ca32_getfs)) ||
1996                get_user(karg->ca_version, &arg->ca32_version) ||
1997                __copy_from_user(&karg->ca_getfs.gd_addr,
1998                                &arg->ca32_getfs.gd32_addr,
1999                                (sizeof(struct sockaddr))) ||
2000                __copy_from_user(&karg->ca_getfs.gd_path,
2001                                &arg->ca32_getfs.gd32_path,
2002                                (NFS_MAXPATHLEN+1)) ||
2003                __get_user(karg->ca_getfs.gd_maxlen,
2004                                &arg->ca32_getfs.gd32_maxlen))
2005                return -EFAULT;
2006
2007        return 0;
2008}
2009
2010/* This really doesn't need translations, we are only passing
2011 * back a union which contains opaque nfs file handle data.
2012 */
2013static int compat_nfs_getfh_res_trans(union nfsctl_res *kres,
2014                                union compat_nfsctl_res __user *res)
2015{
2016        int err;
2017
2018        err = copy_to_user(res, kres, sizeof(*res));
2019
2020        return (err) ? -EFAULT : 0;
2021}
2022
2023asmlinkage long compat_sys_nfsservctl(int cmd,
2024                                struct compat_nfsctl_arg __user *arg,
2025                                union compat_nfsctl_res __user *res)
2026{
2027        struct nfsctl_arg *karg;
2028        union nfsctl_res *kres;
2029        mm_segment_t oldfs;
2030        int err;
2031
2032        karg = kmalloc(sizeof(*karg), GFP_USER);
2033        kres = kmalloc(sizeof(*kres), GFP_USER);
2034        if(!karg || !kres) {
2035                err = -ENOMEM;
2036                goto done;
2037        }
2038
2039        switch(cmd) {
2040        case NFSCTL_SVC:
2041                err = compat_nfs_svc_trans(karg, arg);
2042                break;
2043
2044        case NFSCTL_ADDCLIENT:
2045                err = compat_nfs_clnt_trans(karg, arg);
2046                break;
2047
2048        case NFSCTL_DELCLIENT:
2049                err = compat_nfs_clnt_trans(karg, arg);
2050                break;
2051
2052        case NFSCTL_EXPORT:
2053        case NFSCTL_UNEXPORT:
2054                err = compat_nfs_exp_trans(karg, arg);
2055                break;
2056
2057        case NFSCTL_GETFD:
2058                err = compat_nfs_getfd_trans(karg, arg);
2059                break;
2060
2061        case NFSCTL_GETFS:
2062                err = compat_nfs_getfs_trans(karg, arg);
2063                break;
2064
2065        default:
2066                err = -EINVAL;
2067                break;
2068        }
2069
2070        if (err)
2071                goto done;
2072
2073        oldfs = get_fs();
2074        set_fs(KERNEL_DS);
2075        /* The __user pointer casts are valid because of the set_fs() */
2076        err = sys_nfsservctl(cmd, (void __user *) karg, (void __user *) kres);
2077        set_fs(oldfs);
2078
2079        if (err)
2080                goto done;
2081
2082        if((cmd == NFSCTL_GETFD) ||
2083           (cmd == NFSCTL_GETFS))
2084                err = compat_nfs_getfh_res_trans(kres, res);
2085
2086done:
2087        kfree(karg);
2088        kfree(kres);
2089        return err;
2090}
2091#else /* !NFSD */
2092long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
2093{
2094        return sys_ni_syscall();
2095}
2096#endif
2097
2098#ifdef CONFIG_EPOLL
2099
2100#ifdef HAVE_SET_RESTORE_SIGMASK
2101asmlinkage long compat_sys_epoll_pwait(int epfd,
2102                        struct compat_epoll_event __user *events,
2103                        int maxevents, int timeout,
2104                        const compat_sigset_t __user *sigmask,
2105                        compat_size_t sigsetsize)
2106{
2107        long err;
2108        compat_sigset_t csigmask;
2109        sigset_t ksigmask, sigsaved;
2110
2111        /*
2112         * If the caller wants a certain signal mask to be set during the wait,
2113         * we apply it here.
2114         */
2115        if (sigmask) {
2116                if (sigsetsize != sizeof(compat_sigset_t))
2117                        return -EINVAL;
2118                if (copy_from_user(&csigmask, sigmask, sizeof(csigmask)))
2119                        return -EFAULT;
2120                sigset_from_compat(&ksigmask, &csigmask);
2121                sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
2122                sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
2123        }
2124
2125        err = sys_epoll_wait(epfd, events, maxevents, timeout);
2126
2127        /*
2128         * If we changed the signal mask, we need to restore the original one.
2129         * In case we've got a signal while waiting, we do not restore the
2130         * signal mask yet, and we allow do_signal() to deliver the signal on
2131         * the way back to userspace, before the signal mask is restored.
2132         */
2133        if (sigmask) {
2134                if (err == -EINTR) {
2135                        memcpy(&current->saved_sigmask, &sigsaved,
2136                               sizeof(sigsaved));
2137                        set_restore_sigmask();
2138                } else
2139                        sigprocmask(SIG_SETMASK, &sigsaved, NULL);
2140        }
2141
2142        return err;
2143}
2144#endif /* HAVE_SET_RESTORE_SIGMASK */
2145
2146#endif /* CONFIG_EPOLL */
2147
2148#ifdef CONFIG_SIGNALFD
2149
2150asmlinkage long compat_sys_signalfd4(int ufd,
2151                                     const compat_sigset_t __user *sigmask,
2152                                     compat_size_t sigsetsize, int flags)
2153{
2154        compat_sigset_t ss32;
2155        sigset_t tmp;
2156        sigset_t __user *ksigmask;
2157
2158        if (sigsetsize != sizeof(compat_sigset_t))
2159                return -EINVAL;
2160        if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
2161                return -EFAULT;
2162        sigset_from_compat(&tmp, &ss32);
2163        ksigmask = compat_alloc_user_space(sizeof(sigset_t));
2164        if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
2165                return -EFAULT;
2166
2167        return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
2168}
2169
2170asmlinkage long compat_sys_signalfd(int ufd,
2171                                    const compat_sigset_t __user *sigmask,
2172                                    compat_size_t sigsetsize)
2173{
2174        return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0);
2175}
2176#endif /* CONFIG_SIGNALFD */
2177
2178#ifdef CONFIG_TIMERFD
2179
2180asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
2181                                   const struct compat_itimerspec __user *utmr,
2182                                   struct compat_itimerspec __user *otmr)
2183{
2184        int error;
2185        struct itimerspec t;
2186        struct itimerspec __user *ut;
2187
2188        if (get_compat_itimerspec(&t, utmr))
2189                return -EFAULT;
2190        ut = compat_alloc_user_space(2 * sizeof(struct itimerspec));
2191        if (copy_to_user(&ut[0], &t, sizeof(t)))
2192                return -EFAULT;
2193        error = sys_timerfd_settime(ufd, flags, &ut[0], &ut[1]);
2194        if (!error && otmr)
2195                error = (copy_from_user(&t, &ut[1], sizeof(struct itimerspec)) ||
2196                         put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
2197
2198        return error;
2199}
2200
2201asmlinkage long compat_sys_timerfd_gettime(int ufd,
2202                                   struct compat_itimerspec __user *otmr)
2203{
2204        int error;
2205        struct itimerspec t;
2206        struct itimerspec __user *ut;
2207
2208        ut = compat_alloc_user_space(sizeof(struct itimerspec));
2209        error = sys_timerfd_gettime(ufd, ut);
2210        if (!error)
2211                error = (copy_from_user(&t, ut, sizeof(struct itimerspec)) ||
2212                         put_compat_itimerspec(otmr, &t)) ? -EFAULT: 0;
2213
2214        return error;
2215}
2216
2217#endif /* CONFIG_TIMERFD */
2218