RHEL4/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/linkage.h>
  19#include <linux/compat.h>
  20#include <linux/errno.h>
  21#include <linux/time.h>
  22#include <linux/fs.h>
  23#include <linux/fcntl.h>
  24#include <linux/namei.h>
  25#include <linux/file.h>
  26#include <linux/vfs.h>
  27#include <linux/ioctl32.h>
  28#include <linux/init.h>
  29#include <linux/sockios.h>      /* for SIOCDEVPRIVATE */
  30#include <linux/smb.h>
  31#include <linux/smb_mount.h>
  32#include <linux/ncp_mount.h>
  33#include <linux/nfs4_mount.h>
  34#include <linux/smp_lock.h>
  35#include <linux/syscalls.h>
  36#include <linux/ctype.h>
  37#include <linux/module.h>
  38#include <linux/dirent.h>
  39#include <linux/dnotify.h>
  40#include <linux/highuid.h>
  41#include <linux/sunrpc/svc.h>
  42#include <linux/nfsd/nfsd.h>
  43#include <linux/nfsd/syscall.h>
  44#include <linux/personality.h>
  45#include <linux/rwsem.h>
  46
  47#include <net/sock.h>           /* siocdevprivate_ioctl */
  48
  49#include <asm/uaccess.h>
  50#include <asm/mmu_context.h>
  51
  52/*
  53 * Not all architectures have sys_utime, so implement this in terms
  54 * of sys_utimes.
  55 */
  56asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
  57{
  58        struct timeval tv[2];
  59
  60        if (t) {
  61                if (get_user(tv[0].tv_sec, &t->actime) ||
  62                    get_user(tv[1].tv_sec, &t->modtime))
  63                        return -EFAULT;
  64                tv[0].tv_usec = 0;
  65                tv[1].tv_usec = 0;
  66        }
  67        return do_utimes(filename, t ? tv : NULL);
  68}
  69
  70asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
  71{
  72        struct timeval tv[2];
  73
  74        if (t) { 
  75                if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
  76                    get_user(tv[0].tv_usec, &t[0].tv_usec) ||
  77                    get_user(tv[1].tv_sec, &t[1].tv_sec) ||
  78                    get_user(tv[1].tv_usec, &t[1].tv_usec))
  79                        return -EFAULT; 
  80        } 
  81        return do_utimes(filename, t ? tv : NULL);
  82}
  83
  84asmlinkage long compat_sys_newstat(char __user * filename,
  85                struct compat_stat __user *statbuf)
  86{
  87        struct kstat64 stat;
  88        int error = vfs_stat64(filename, &stat);
  89
  90        if (!error)
  91                error = cp_compat_stat(&stat, statbuf);
  92        return error;
  93}
  94
  95asmlinkage long compat_sys_newlstat(char __user * filename,
  96                struct compat_stat __user *statbuf)
  97{
  98        struct kstat64 stat;
  99        int error = vfs_lstat64(filename, &stat);
 100
 101        if (!error)
 102                error = cp_compat_stat(&stat, statbuf);
 103        return error;
 104}
 105
 106asmlinkage long compat_sys_newfstat(unsigned int fd,
 107                struct compat_stat __user * statbuf)
 108{
 109        struct kstat64 stat;
 110        int error = vfs_fstat64(fd, &stat);
 111
 112        if (!error)
 113                error = cp_compat_stat(&stat, statbuf);
 114        return error;
 115}
 116
 117static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
 118{
 119        
 120        if (sizeof ubuf->f_blocks == 4) {
 121                if ((kbuf->f_blocks | kbuf->f_bfree |
 122                     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
 123                    0xffffffff00000000ULL)
 124                        return -EOVERFLOW;
 125        }
 126        if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 127            __put_user(kbuf->f_type, &ubuf->f_type) ||
 128            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 129            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
 130            __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
 131            __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
 132            __put_user(kbuf->f_files, &ubuf->f_files) ||
 133            __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
 134            __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 135            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 136            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 137            __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
 138            __put_user(0, &ubuf->f_spare[0]) || 
 139            __put_user(0, &ubuf->f_spare[1]) || 
 140            __put_user(0, &ubuf->f_spare[2]) || 
 141            __put_user(0, &ubuf->f_spare[3]) || 
 142            __put_user(0, &ubuf->f_spare[4]))
 143                return -EFAULT;
 144        return 0;
 145}
 146
 147/*
 148 * The following statfs calls are copies of code from fs/open.c and
 149 * should be checked against those from time to time
 150 */
 151asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf)
 152{
 153        struct nameidata nd;
 154        int error;
 155
 156        error = user_path_walk(path, &nd);
 157        if (!error) {
 158                struct kstatfs tmp;
 159                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
 160                if (!error && put_compat_statfs(buf, &tmp))
 161                        error = -EFAULT;
 162                path_release(&nd);
 163        }
 164        return error;
 165}
 166
 167asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
 168{
 169        struct file * file;
 170        struct kstatfs tmp;
 171        int error;
 172
 173        error = -EBADF;
 174        file = fget(fd);
 175        if (!file)
 176                goto out;
 177        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
 178        if (!error && put_compat_statfs(buf, &tmp))
 179                error = -EFAULT;
 180        fput(file);
 181out:
 182        return error;
 183}
 184
 185static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
 186{
 187        if (sizeof ubuf->f_blocks == 4) {
 188                if ((kbuf->f_blocks | kbuf->f_bfree |
 189                     kbuf->f_bavail | kbuf->f_files | kbuf->f_ffree) &
 190                    0xffffffff00000000ULL)
 191                        return -EOVERFLOW;
 192        }
 193        if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
 194            __put_user(kbuf->f_type, &ubuf->f_type) ||
 195            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
 196            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
 197            __put_user(kbuf->f_bfree, &ubuf->f_bfree) ||
 198            __put_user(kbuf->f_bavail, &ubuf->f_bavail) ||
 199            __put_user(kbuf->f_files, &ubuf->f_files) ||
 200            __put_user(kbuf->f_ffree, &ubuf->f_ffree) ||
 201            __put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
 202            __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
 203            __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
 204            __put_user(kbuf->f_frsize, &ubuf->f_frsize))
 205                return -EFAULT;
 206        return 0;
 207}
 208
 209asmlinkage long compat_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf)
 210{
 211        struct nameidata nd;
 212        int error;
 213
 214        if (sz != sizeof(*buf))
 215                return -EINVAL;
 216
 217        error = user_path_walk(path, &nd);
 218        if (!error) {
 219                struct kstatfs tmp;
 220                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
 221                if (!error && put_compat_statfs64(buf, &tmp))
 222                        error = -EFAULT;
 223                path_release(&nd);
 224        }
 225        return error;
 226}
 227
 228asmlinkage long compat_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
 229{
 230        struct file * file;
 231        struct kstatfs tmp;
 232        int error;
 233
 234        if (sz != sizeof(*buf))
 235                return -EINVAL;
 236
 237        error = -EBADF;
 238        file = fget(fd);
 239        if (!file)
 240                goto out;
 241        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
 242        if (!error && put_compat_statfs64(buf, &tmp))
 243                error = -EFAULT;
 244        fput(file);
 245out:
 246        return error;
 247}
 248
 249/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */
 250
 251#define IOCTL_HASHSIZE 256
 252static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
 253static DECLARE_RWSEM(ioctl32_sem);
 254
 255extern struct ioctl_trans ioctl_start[];
 256extern int ioctl_table_size;
 257
 258static inline unsigned long ioctl32_hash(unsigned long cmd)
 259{
 260        return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
 261}
 262
 263static void ioctl32_insert_translation(struct ioctl_trans *trans)
 264{
 265        unsigned long hash;
 266        struct ioctl_trans *t;
 267
 268        init_rwsem(&trans->inuse);
 269
 270        hash = ioctl32_hash (trans->cmd);
 271        if (!ioctl32_hash_table[hash])
 272                ioctl32_hash_table[hash] = trans;
 273        else {
 274                t = ioctl32_hash_table[hash];
 275                while (t->next)
 276                        t = t->next;
 277                trans->next = NULL;
 278                t->next = trans;
 279        }
 280}
 281
 282static int __init init_sys32_ioctl(void)
 283{
 284        int i;
 285
 286        for (i = 0; i < ioctl_table_size; i++) {
 287                if (ioctl_start[i].next != 0) { 
 288                        printk("ioctl translation %d bad\n",i); 
 289                        return -1;
 290                }
 291
 292                ioctl32_insert_translation(&ioctl_start[i]);
 293        }
 294        return 0;
 295}
 296
 297__initcall(init_sys32_ioctl);
 298
 299int register_ioctl32_conversion(unsigned int cmd,
 300                                ioctl_trans_handler_t handler)
 301{
 302        struct ioctl_trans *t;
 303        struct ioctl_trans *new_t;
 304        unsigned long hash = ioctl32_hash(cmd);
 305
 306        new_t = kmalloc(sizeof(*new_t), GFP_KERNEL);
 307        if (!new_t)
 308                return -ENOMEM;
 309
 310        down_write(&ioctl32_sem);
 311        for (t = ioctl32_hash_table[hash]; t; t = t->next) {
 312                if (t->cmd == cmd) {
 313                        printk(KERN_ERR "Trying to register duplicated ioctl32 "
 314                                        "handler %x\n", cmd);
 315                        up_write(&ioctl32_sem);
 316                        kfree(new_t);
 317                        return -EINVAL; 
 318                }
 319        }
 320        new_t->next = NULL;
 321        new_t->cmd = cmd;
 322        new_t->handler = handler;
 323        ioctl32_insert_translation(new_t);
 324
 325        up_write(&ioctl32_sem);
 326        return 0;
 327}
 328EXPORT_SYMBOL(register_ioctl32_conversion);
 329
 330static inline int builtin_ioctl(struct ioctl_trans *t)
 331{ 
 332        return t >= ioctl_start && t < (ioctl_start + ioctl_table_size);
 333} 
 334
 335/* Problem: 
 336   This function cannot unregister duplicate ioctls, because they are not
 337   unique.
 338   When they happen we need to extend the prototype to pass the handler too. */
 339
 340int unregister_ioctl32_conversion(unsigned int cmd)
 341{
 342        unsigned long hash = ioctl32_hash(cmd);
 343        struct ioctl_trans **pt, *t;
 344
 345        down_write(&ioctl32_sem);
 346        for (pt = ioctl32_hash_table + hash; (t = *pt) != NULL; pt = &t->next) {
 347                if (t->cmd != cmd)
 348                        continue;
 349                if (builtin_ioctl(t)) {
 350                        printk(KERN_ERR "%p tried to unregister builtin ioctl %x\n",
 351                                __builtin_return_address(0), cmd);
 352                        goto out;
 353                }
 354
 355                *pt = t->next;
 356                up_write(&ioctl32_sem);
 357
 358                down_write(&t->inuse);  /* wait for ->handler() in flight */
 359                up_write(&t->inuse);
 360                kfree(t);
 361
 362                return 0;
 363        }
 364        printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd);
 365out:
 366        up_write(&ioctl32_sem);
 367        return -EINVAL;
 368}
 369EXPORT_SYMBOL(unregister_ioctl32_conversion); 
 370
 371asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
 372                                unsigned long arg)
 373{
 374        struct file * filp;
 375        int error = -EBADF;
 376        struct ioctl_trans *t;
 377
 378        filp = fget(fd);
 379        if(!filp)
 380                goto out2;
 381
 382        if (!filp->f_op || !filp->f_op->ioctl) {
 383                error = sys_ioctl (fd, cmd, arg);
 384                goto out;
 385        }
 386
 387        down_read(&ioctl32_sem);
 388
 389        t = ioctl32_hash_table[ioctl32_hash (cmd)];
 390
 391        while (t && t->cmd != cmd)
 392                t = t->next;
 393        if (t) {
 394                if (t->handler) {
 395                        down_read(&t->inuse);
 396                        up_read(&ioctl32_sem);
 397                        lock_kernel();
 398                        error = t->handler(fd, cmd, arg, filp);
 399                        unlock_kernel();
 400                        up_read(&t->inuse);
 401                } else {
 402                        up_read(&ioctl32_sem);
 403                        error = sys_ioctl(fd, cmd, arg);
 404                }
 405        } else {
 406                up_read(&ioctl32_sem);
 407                if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
 408                        error = siocdevprivate_ioctl(fd, cmd, arg);
 409                } else {
 410                        static int count;
 411                        if (++count <= 50) {
 412                                char buf[10];
 413                                char *fn = "?";
 414                                char *path;
 415
 416                                path = (char *)__get_free_page(GFP_KERNEL);
 417
 418                                /* find the name of the device. */
 419                                if (path) {
 420                                        fn = d_path(filp->f_dentry,
 421                                                filp->f_vfsmnt, path,
 422                                                PAGE_SIZE);
 423                                        if (IS_ERR(fn))
 424                                                fn = "?";
 425                                }
 426
 427                                sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
 428                                if (!isprint(buf[1]))
 429                                    sprintf(buf, "%02x", buf[1]);
 430                                printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
 431                                        "cmd(%08x){%s} arg(%08x) on %s\n",
 432                                        current->comm, current->pid,
 433                                        (int)fd, (unsigned int)cmd, buf,
 434                                        (unsigned int)arg, fn);
 435                                if (path)
 436                                        free_page((unsigned long)path);
 437                        }
 438                        error = -EINVAL;
 439                }
 440        }
 441out:
 442        fput(filp);
 443out2:
 444        return error;
 445}
 446
 447static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 448{
 449        if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
 450            __get_user(kfl->l_type, &ufl->l_type) ||
 451            __get_user(kfl->l_whence, &ufl->l_whence) ||
 452            __get_user(kfl->l_start, &ufl->l_start) ||
 453            __get_user(kfl->l_len, &ufl->l_len) ||
 454            __get_user(kfl->l_pid, &ufl->l_pid))
 455                return -EFAULT;
 456        return 0;
 457}
 458
 459static int put_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
 460{
 461        if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
 462            __put_user(kfl->l_type, &ufl->l_type) ||
 463            __put_user(kfl->l_whence, &ufl->l_whence) ||
 464            __put_user(kfl->l_start, &ufl->l_start) ||
 465            __put_user(kfl->l_len, &ufl->l_len) ||
 466            __put_user(kfl->l_pid, &ufl->l_pid))
 467                return -EFAULT;
 468        return 0;
 469}
 470
 471#ifndef HAVE_ARCH_GET_COMPAT_FLOCK64
 472static int get_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
 473{
 474        if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
 475            __get_user(kfl->l_type, &ufl->l_type) ||
 476            __get_user(kfl->l_whence, &ufl->l_whence) ||
 477            __get_user(kfl->l_start, &ufl->l_start) ||
 478            __get_user(kfl->l_len, &ufl->l_len) ||
 479            __get_user(kfl->l_pid, &ufl->l_pid))
 480                return -EFAULT;
 481        return 0;
 482}
 483#endif
 484
 485#ifndef HAVE_ARCH_PUT_COMPAT_FLOCK64
 486static int put_compat_flock64(struct flock *kfl, struct compat_flock64 __user *ufl)
 487{
 488        if (!access_ok(VERIFY_WRITE, ufl, sizeof(*ufl)) ||
 489            __put_user(kfl->l_type, &ufl->l_type) ||
 490            __put_user(kfl->l_whence, &ufl->l_whence) ||
 491            __put_user(kfl->l_start, &ufl->l_start) ||
 492            __put_user(kfl->l_len, &ufl->l_len) ||
 493            __put_user(kfl->l_pid, &ufl->l_pid))
 494                return -EFAULT;
 495        return 0;
 496}
 497#endif
 498
 499asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
 500                unsigned long arg)
 501{
 502        mm_segment_t old_fs;
 503        struct flock f;
 504        long ret;
 505
 506        switch (cmd) {
 507        case F_GETLK:
 508        case F_SETLK:
 509        case F_SETLKW:
 510                ret = get_compat_flock(&f, compat_ptr(arg));
 511                if (ret != 0)
 512                        break;
 513                old_fs = get_fs();
 514                set_fs(KERNEL_DS);
 515                ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 516                set_fs(old_fs);
 517                if ((cmd == F_GETLK) && (ret == 0)) {
 518                        if ((compat_off_t) f.l_start != f.l_start ||
 519                            (compat_off_t) f.l_len != f.l_len)
 520                                ret = -EOVERFLOW;
 521                        else
 522                                ret = put_compat_flock(&f, compat_ptr(arg));
 523                }
 524                break;
 525
 526        case F_GETLK64:
 527        case F_SETLK64:
 528        case F_SETLKW64:
 529                ret = get_compat_flock64(&f, compat_ptr(arg));
 530                if (ret != 0)
 531                        break;
 532                old_fs = get_fs();
 533                set_fs(KERNEL_DS);
 534                ret = sys_fcntl(fd, (cmd == F_GETLK64) ? F_GETLK :
 535                                ((cmd == F_SETLK64) ? F_SETLK : F_SETLKW),
 536                                (unsigned long)&f);
 537                set_fs(old_fs);
 538                if ((cmd == F_GETLK64) && (ret == 0)) {
 539                        if ((compat_loff_t) f.l_start != f.l_start ||
 540                            (compat_loff_t) f.l_len != f.l_len)
 541                                ret = -EOVERFLOW;
 542                        else
 543                                ret = put_compat_flock64(&f, compat_ptr(arg));
 544                }
 545                break;
 546
 547        default:
 548                ret = sys_fcntl(fd, cmd, arg);
 549                break;
 550        }
 551        return ret;
 552}
 553
 554asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
 555                unsigned long arg)
 556{
 557        if ((cmd == F_GETLK64) || (cmd == F_SETLK64) || (cmd == F_SETLKW64))
 558                return -EINVAL;
 559        return compat_sys_fcntl64(fd, cmd, arg);
 560}
 561
 562asmlinkage long
 563compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p)
 564{
 565        long ret;
 566        aio_context_t ctx64;
 567
 568        mm_segment_t oldfs = get_fs();
 569        if (unlikely(get_user(ctx64, ctx32p)))
 570                return -EFAULT;
 571
 572        set_fs(KERNEL_DS);
 573        /* The __user pointer cast is valid because of the set_fs() */
 574        ret = sys_io_setup(nr_reqs, (aio_context_t __user *) &ctx64);
 575        set_fs(oldfs);
 576        /* truncating is ok because it's a user address */
 577        if (!ret)
 578                ret = put_user((u32) ctx64, ctx32p);
 579        return ret;
 580}
 581
 582asmlinkage long
 583compat_sys_io_getevents(aio_context_t ctx_id,
 584                                 unsigned long min_nr,
 585                                 unsigned long nr,
 586                                 struct io_event __user *events,
 587                                 struct compat_timespec __user *timeout)
 588{
 589        long ret;
 590        struct timespec t;
 591        struct timespec __user *ut = NULL;
 592
 593        ret = -EFAULT;
 594        if (unlikely(!access_ok(VERIFY_WRITE, events, 
 595                                nr * sizeof(struct io_event))))
 596                goto out;
 597        if (timeout) {
 598                if (get_compat_timespec(&t, timeout))
 599                        goto out;
 600
 601                ut = compat_alloc_user_space(sizeof(*ut));
 602                if (copy_to_user(ut, &t, sizeof(t)) )
 603                        goto out;
 604        } 
 605        ret = sys_io_getevents(ctx_id, min_nr, nr, events, ut);
 606out:
 607        return ret;
 608}
 609
 610static inline long
 611copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
 612{
 613        compat_uptr_t uptr;
 614        int i;
 615
 616        for (i = 0; i < nr; ++i) {
 617                if (get_user(uptr, ptr32 + i))
 618                        return -EFAULT;
 619                if (put_user(compat_ptr(uptr), ptr64 + i))
 620                        return -EFAULT;
 621        }
 622        return 0;
 623}
 624
 625#define MAX_AIO_SUBMITS         (PAGE_SIZE/sizeof(struct iocb *))
 626
 627asmlinkage long
 628compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
 629{
 630        struct iocb __user * __user *iocb64; 
 631        long ret;
 632
 633        if (unlikely(nr < 0))
 634                return -EINVAL;
 635
 636        if (nr > MAX_AIO_SUBMITS)
 637                nr = MAX_AIO_SUBMITS;
 638        
 639        iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
 640        ret = copy_iocb(nr, iocb, iocb64);
 641        if (!ret)
 642                ret = sys_io_submit(ctx_id, nr, iocb64);
 643        return ret;
 644}
 645
 646struct compat_ncp_mount_data {
 647        compat_int_t version;
 648        compat_uint_t ncp_fd;
 649        compat_uid_t mounted_uid;
 650        compat_pid_t wdog_pid;
 651        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
 652        compat_uint_t time_out;
 653        compat_uint_t retry_count;
 654        compat_uint_t flags;
 655        compat_uid_t uid;
 656        compat_gid_t gid;
 657        compat_mode_t file_mode;
 658        compat_mode_t dir_mode;
 659};
 660
 661struct compat_ncp_mount_data_v4 {
 662        compat_int_t version;
 663        compat_ulong_t flags;
 664        compat_ulong_t mounted_uid;
 665        compat_long_t wdog_pid;
 666        compat_uint_t ncp_fd;
 667        compat_uint_t time_out;
 668        compat_uint_t retry_count;
 669        compat_ulong_t uid;
 670        compat_ulong_t gid;
 671        compat_ulong_t file_mode;
 672        compat_ulong_t dir_mode;
 673};
 674
 675static void *do_ncp_super_data_conv(void *raw_data)
 676{
 677        int version = *(unsigned int *)raw_data;
 678
 679        if (version == 3) {
 680                struct compat_ncp_mount_data *c_n = raw_data;
 681                struct ncp_mount_data *n = raw_data;
 682
 683                n->dir_mode = c_n->dir_mode;
 684                n->file_mode = c_n->file_mode;
 685                n->gid = c_n->gid;
 686                n->uid = c_n->uid;
 687                memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
 688                n->wdog_pid = c_n->wdog_pid;
 689                n->mounted_uid = c_n->mounted_uid;
 690        } else if (version == 4) {
 691                struct compat_ncp_mount_data_v4 *c_n = raw_data;
 692                struct ncp_mount_data_v4 *n = raw_data;
 693
 694                n->dir_mode = c_n->dir_mode;
 695                n->file_mode = c_n->file_mode;
 696                n->gid = c_n->gid;
 697                n->uid = c_n->uid;
 698                n->retry_count = c_n->retry_count;
 699                n->time_out = c_n->time_out;
 700                n->ncp_fd = c_n->ncp_fd;
 701                n->wdog_pid = c_n->wdog_pid;
 702                n->mounted_uid = c_n->mounted_uid;
 703                n->flags = c_n->flags;
 704        } else if (version != 5) {
 705                return NULL;
 706        }
 707
 708        return raw_data;
 709}
 710
 711struct compat_smb_mount_data {
 712        compat_int_t version;
 713        compat_uid_t mounted_uid;
 714        compat_uid_t uid;
 715        compat_gid_t gid;
 716        compat_mode_t file_mode;
 717        compat_mode_t dir_mode;
 718};
 719
 720static void *do_smb_super_data_conv(void *raw_data)
 721{
 722        struct smb_mount_data *s = raw_data;
 723        struct compat_smb_mount_data *c_s = raw_data;
 724
 725        if (c_s->version != SMB_MOUNT_OLDVERSION)
 726                goto out;
 727        s->dir_mode = c_s->dir_mode;
 728        s->file_mode = c_s->file_mode;
 729        s->gid = c_s->gid;
 730        s->uid = c_s->uid;
 731        s->mounted_uid = c_s->mounted_uid;
 732 out:
 733        return raw_data;
 734}
 735
 736struct compat_nfs_string {
 737        compat_uint_t len;
 738        compat_uptr_t __user data;
 739};
 740
 741static inline void compat_nfs_string(struct nfs_string *dst,
 742                                     struct compat_nfs_string *src)
 743{
 744        dst->data = compat_ptr(src->data);
 745        dst->len = src->len;
 746}
 747
 748struct compat_nfs4_mount_data_v1 {
 749        compat_int_t version;
 750        compat_int_t flags;
 751        compat_int_t rsize;
 752        compat_int_t wsize;
 753        compat_int_t timeo;
 754        compat_int_t retrans;
 755        compat_int_t acregmin;
 756        compat_int_t acregmax;
 757        compat_int_t acdirmin;
 758        compat_int_t acdirmax;
 759        struct compat_nfs_string client_addr;
 760        struct compat_nfs_string mnt_path;
 761        struct compat_nfs_string hostname;
 762        compat_uint_t host_addrlen;
 763        compat_uptr_t __user host_addr;
 764        compat_int_t proto;
 765        compat_int_t auth_flavourlen;
 766        compat_uptr_t __user auth_flavours;
 767};
 768
 769static int do_nfs4_super_data_conv(void *raw_data)
 770{
 771        int version = *(compat_uint_t *) raw_data;
 772
 773        if (version == 1) {
 774                struct compat_nfs4_mount_data_v1 *raw = raw_data;
 775                struct nfs4_mount_data *real = raw_data;
 776
 777                /* copy the fields backwards */
 778                real->auth_flavours = compat_ptr(raw->auth_flavours);
 779                real->auth_flavourlen = raw->auth_flavourlen;
 780                real->proto = raw->proto;
 781                real->host_addr = compat_ptr(raw->host_addr);
 782                real->host_addrlen = raw->host_addrlen;
 783                compat_nfs_string(&real->hostname, &raw->hostname);
 784                compat_nfs_string(&real->mnt_path, &raw->mnt_path);
 785                compat_nfs_string(&real->client_addr, &raw->client_addr);
 786                real->acdirmax = raw->acdirmax;
 787                real->acdirmin = raw->acdirmin;
 788                real->acregmax = raw->acregmax;
 789                real->acregmin = raw->acregmin;
 790                real->retrans = raw->retrans;
 791                real->timeo = raw->timeo;
 792                real->wsize = raw->wsize;
 793                real->rsize = raw->rsize;
 794                real->flags = raw->flags;
 795                real->version = raw->version;
 796        }
 797        else {
 798                return -EINVAL;
 799        }
 800
 801        return 0;
 802}
 803
 804extern int copy_mount_options (const void __user *, unsigned long *);
 805
 806#define SMBFS_NAME      "smbfs"
 807#define NCPFS_NAME      "ncpfs"
 808#define NFS4_NAME       "nfs4"
 809
 810asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
 811                                 char __user * type, unsigned long flags,
 812                                 void __user * data)
 813{
 814        unsigned long type_page;
 815        unsigned long data_page;
 816        unsigned long dev_page;
 817        char *dir_page;
 818        int retval;
 819
 820        retval = copy_mount_options (type, &type_page);
 821        if (retval < 0)
 822                goto out;
 823
 824        dir_page = getname(dir_name);
 825        retval = PTR_ERR(dir_page);
 826        if (IS_ERR(dir_page))
 827                goto out1;
 828
 829        retval = copy_mount_options (dev_name, &dev_page);
 830        if (retval < 0)
 831                goto out2;
 832
 833        retval = copy_mount_options (data, &data_page);
 834        if (retval < 0)
 835                goto out3;
 836
 837        retval = -EINVAL;
 838
 839        if (type_page && data_page) {
 840                if (!strcmp((char *)type_page, SMBFS_NAME)) {
 841                        do_smb_super_data_conv((void *)data_page);
 842                } else if (!strcmp((char *)type_page, NCPFS_NAME)) {
 843                        do_ncp_super_data_conv((void *)data_page);
 844                } else if (!strcmp((char *)type_page, NFS4_NAME)) {
 845                        if (do_nfs4_super_data_conv((void *) data_page))
 846                                goto out4;
 847                }
 848        }
 849
 850        lock_kernel();
 851        retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
 852                        flags, (void*)data_page);
 853        unlock_kernel();
 854
 855 out4:
 856        free_page(data_page);
 857 out3:
 858        free_page(dev_page);
 859 out2:
 860        putname(dir_page);
 861 out1:
 862        free_page(type_page);
 863 out:
 864        return retval;
 865}
 866
 867#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
 868#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & \
 869                                ~(sizeof(compat_long_t)-1))
 870
 871struct compat_old_linux_dirent {
 872        compat_ulong_t  d_ino;
 873        compat_ulong_t  d_offset;
 874        unsigned short  d_namlen;
 875        char            d_name[1];
 876};
 877
 878struct compat_readdir_callback {
 879        struct compat_old_linux_dirent __user *dirent;
 880        int result;
 881};
 882
 883static int compat_fillonedir(void *__buf, const char *name, int namlen,
 884                        loff_t offset, ino_t ino, unsigned int d_type)
 885{
 886        struct compat_readdir_callback *buf = __buf;
 887        struct compat_old_linux_dirent __user *dirent;
 888
 889        if (buf->result)
 890                return -EINVAL;
 891        buf->result++;
 892        dirent = buf->dirent;
 893        if (!access_ok(VERIFY_WRITE, dirent,
 894                        (unsigned long)(dirent->d_name + namlen + 1) -
 895                                (unsigned long)dirent))
 896                goto efault;
 897        if (    __put_user(ino, &dirent->d_ino) ||
 898                __put_user(offset, &dirent->d_offset) ||
 899                __put_user(namlen, &dirent->d_namlen) ||
 900                __copy_to_user(dirent->d_name, name, namlen) ||
 901                __put_user(0, dirent->d_name + namlen))
 902                goto efault;
 903        return 0;
 904efault:
 905        buf->result = -EFAULT;
 906        return -EFAULT;
 907}
 908
 909asmlinkage long compat_old_readdir(unsigned int fd,
 910        struct compat_old_linux_dirent __user *dirent, unsigned int count)
 911{
 912        int error;
 913        struct file *file;
 914        struct compat_readdir_callback buf;
 915
 916        error = -EBADF;
 917        file = fget(fd);
 918        if (!file)
 919                goto out;
 920
 921        buf.result = 0;
 922        buf.dirent = dirent;
 923
 924        error = vfs_readdir(file, compat_fillonedir, &buf);
 925        if (error >= 0)
 926                error = buf.result;
 927
 928        fput(file);
 929out:
 930        return error;
 931}
 932
 933struct compat_linux_dirent {
 934        compat_ulong_t  d_ino;
 935        compat_ulong_t  d_off;
 936        unsigned short  d_reclen;
 937        char            d_name[1];
 938};
 939
 940struct compat_getdents_callback {
 941        struct compat_linux_dirent __user *current_dir;
 942        struct compat_linux_dirent __user *previous;
 943        int count;
 944        int error;
 945};
 946
 947static int compat_filldir(void *__buf, const char *name, int namlen,
 948                loff_t offset, ino_t ino, unsigned int d_type)
 949{
 950        struct compat_linux_dirent __user * dirent;
 951        struct compat_getdents_callback *buf = __buf;
 952        int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
 953
 954        buf->error = -EINVAL;   /* only used if we fail.. */
 955        if (reclen > buf->count)
 956                return -EINVAL;
 957        dirent = buf->previous;
 958        if (dirent) {
 959                if (__put_user(offset, &dirent->d_off))
 960                        goto efault;
 961        }
 962        dirent = buf->current_dir;
 963        if (__put_user(ino, &dirent->d_ino))
 964                goto efault;
 965        if (__put_user(reclen, &dirent->d_reclen))
 966                goto efault;
 967        if (copy_to_user(dirent->d_name, name, namlen))
 968                goto efault;
 969        if (__put_user(0, dirent->d_name + namlen))
 970                goto efault;
 971        if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
 972                goto efault;
 973        buf->previous = dirent;
 974        dirent = (void __user *)dirent + reclen;
 975        buf->current_dir = dirent;
 976        buf->count -= reclen;
 977        return 0;
 978efault:
 979        buf->error = -EFAULT;
 980        return -EFAULT;
 981}
 982
 983asmlinkage long compat_sys_getdents(unsigned int fd,
 984                struct compat_linux_dirent __user *dirent, unsigned int count)
 985{
 986        struct file * file;
 987        struct compat_linux_dirent __user * lastdirent;
 988        struct compat_getdents_callback buf;
 989        int error;
 990
 991        error = -EFAULT;
 992        if (!access_ok(VERIFY_WRITE, dirent, count))
 993                goto out;
 994
 995        error = -EBADF;
 996        file = fget(fd);
 997        if (!file)
 998                goto out;
 999
1000        buf.current_dir = dirent;
1001        buf.previous = NULL;
1002        buf.count = count;
1003        buf.error = 0;
1004
1005        error = vfs_readdir(file, compat_filldir, &buf);
1006        if (error < 0)
1007                goto out_putf;
1008        error = buf.error;
1009        lastdirent = buf.previous;
1010        if (lastdirent) {
1011                if (put_user(file->f_pos, &lastdirent->d_off))
1012                        error = -EFAULT;
1013                else
1014                        error = count - buf.count;
1015        }
1016
1017out_putf:
1018        fput(file);
1019out:
1020        return error;
1021}
1022
1023#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
1024#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
1025
1026struct compat_getdents_callback64 {
1027        struct linux_dirent64 __user *current_dir;
1028        struct linux_dirent64 __user *previous;
1029        int count;
1030        int error;
1031};
1032
1033static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
1034                     ino_t ino, unsigned int d_type)
1035{
1036        struct linux_dirent64 __user *dirent;
1037        struct compat_getdents_callback64 *buf = __buf;
1038        int jj = NAME_OFFSET(dirent);
1039        int reclen = COMPAT_ROUND_UP64(jj + namlen + 1);
1040        u64 off;
1041
1042        buf->error = -EINVAL;   /* only used if we fail.. */
1043        if (reclen > buf->count)
1044                return -EINVAL;
1045        dirent = buf->previous;
1046
1047        if (dirent) {
1048                if (__put_user_unaligned(offset, &dirent->d_off))
1049                        goto efault;
1050        }
1051        dirent = buf->current_dir;
1052        if (__put_user_unaligned(ino, &dirent->d_ino))
1053                goto efault;
1054        off = 0;
1055        if (__put_user_unaligned(off, &dirent->d_off))
1056                goto efault;
1057        if (__put_user(reclen, &dirent->d_reclen))
1058                goto efault;
1059        if (__put_user(d_type, &dirent->d_type))
1060                goto efault;
1061        if (copy_to_user(dirent->d_name, name, namlen))
1062                goto efault;
1063        if (__put_user(0, dirent->d_name + namlen))
1064                goto efault;
1065        buf->previous = dirent;
1066        dirent = (void __user *)dirent + reclen;
1067        buf->current_dir = dirent;
1068        buf->count -= reclen;
1069        return 0;
1070efault:
1071        buf->error = -EFAULT;
1072        return -EFAULT;
1073}
1074
1075asmlinkage long compat_sys_getdents64(unsigned int fd,
1076                struct linux_dirent64 __user * dirent, unsigned int count)
1077{
1078        struct file * file;
1079        struct linux_dirent64 __user * lastdirent;
1080        struct compat_getdents_callback64 buf;
1081        int error;
1082
1083        error = -EFAULT;
1084        if (!access_ok(VERIFY_WRITE, dirent, count))
1085                goto out;
1086
1087        error = -EBADF;
1088        file = fget(fd);
1089        if (!file)
1090                goto out;
1091
1092        buf.current_dir = dirent;
1093        buf.previous = NULL;
1094        buf.count = count;
1095        buf.error = 0;
1096
1097        error = vfs_readdir(file, compat_filldir64, &buf);
1098        if (error < 0)
1099                goto out_putf;
1100        error = buf.error;
1101        lastdirent = buf.previous;
1102        if (lastdirent) {
1103                typeof(lastdirent->d_off) d_off = file->f_pos;
1104                __put_user_unaligned(d_off, &lastdirent->d_off);
1105                error = count - buf.count;
1106        }
1107
1108out_putf:
1109        fput(file);
1110out:
1111        return error;
1112}
1113#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
1114
1115static ssize_t compat_do_readv_writev(int type, struct file *file,
1116                               const struct compat_iovec __user *uvector,
1117                               unsigned long nr_segs, loff_t *pos)
1118{
1119        typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
1120        typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
1121
1122        compat_ssize_t tot_len;
1123        struct iovec iovstack[UIO_FASTIOV];
1124        struct iovec *iov=iovstack, *vector;
1125        ssize_t ret;
1126        int seg;
1127        io_fn_t fn;
1128        iov_fn_t fnv;
1129        struct inode *inode;
1130
1131        /*
1132         * SuS says "The readv() function *may* fail if the iovcnt argument
1133         * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
1134         * traditionally returned zero for zero segments, so...
1135         */
1136        ret = 0;
1137        if (nr_segs == 0)
1138                goto out;
1139
1140        /*
1141         * First get the "struct iovec" from user memory and
1142         * verify all the pointers
1143         */
1144        ret = -EINVAL;
1145        if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
1146                goto out;
1147        if (!file->f_op)
1148                goto out;
1149        if (nr_segs > UIO_FASTIOV) {
1150                ret = -ENOMEM;
1151                iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
1152                if (!iov)
1153                        goto out;
1154        }
1155        ret = -EFAULT;
1156        if (verify_area(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
1157                goto out;
1158
1159        /*
1160         * Single unix specification:
1161         * We should -EINVAL if an element length is not >= 0 and fitting an
1162         * ssize_t.  The total length is fitting an ssize_t
1163         *
1164         * Be careful here because iov_len is a size_t not an ssize_t
1165         */
1166        tot_len = 0;
1167        vector = iov;
1168        ret = -EINVAL;
1169        for (seg = 0 ; seg < nr_segs; seg++) {
1170                compat_ssize_t tmp = tot_len;
1171                compat_ssize_t len;
1172                compat_uptr_t buf;
1173
1174                if (__get_user(len, &uvector->iov_len) ||
1175                    __get_user(buf, &uvector->iov_base)) {
1176                        ret = -EFAULT;
1177                        goto out;
1178                }
1179                if (len < 0)    /* size_t not fitting an compat_ssize_t .. */
1180                        goto out;
1181                tot_len += len;
1182                if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
1183                        goto out;
1184                vector->iov_base = compat_ptr(buf);
1185                vector->iov_len = (compat_size_t) len;
1186                uvector++;
1187                vector++;
1188        }
1189        if (tot_len == 0) {
1190                ret = 0;
1191                goto out;
1192        }
1193
1194        inode = file->f_dentry->d_inode;
1195        /* VERIFY_WRITE actually means a read, as we write to user space */
1196        ret = locks_verify_area((type == READ
1197                                 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
1198                                inode, file, *pos, tot_len);
1199        if (ret)
1200                goto out;
1201
1202        ret = security_file_permission(file, type == READ ? MAY_READ:MAY_WRITE);
1203        if (ret)
1204                goto out;
1205
1206        fnv = NULL;
1207        if (type == READ) {
1208                fn = file->f_op->read;
1209                fnv = file->f_op->readv;
1210        } else {
1211                fn = (io_fn_t)file->f_op->write;
1212                fnv = file->f_op->writev;
1213        }
1214        if (fnv) {
1215                ret = fnv(file, iov, nr_segs, pos);
1216                goto out;
1217        }
1218
1219        /* Do it by hand, with file-ops */
1220        ret = 0;
1221        vector = iov;
1222        while (nr_segs > 0) {
1223                void __user * base;
1224                size_t len;
1225                ssize_t nr;
1226
1227                base = vector->iov_base;
1228                len = vector->iov_len;
1229                vector++;
1230                nr_segs--;
1231
1232                nr = fn(file, base, len, pos);
1233
1234                if (nr < 0) {
1235                        if (!ret) ret = nr;
1236                        break;
1237                }
1238                ret += nr;
1239                if (nr != len)
1240                        break;
1241        }
1242out:
1243        if (iov != iovstack)
1244                kfree(iov);
1245        if ((ret + (type == READ)) > 0)
1246                dnotify_parent(file->f_dentry,
1247                                (type == READ) ? DN_ACCESS : DN_MODIFY);
1248        return ret;
1249}
1250
1251asmlinkage ssize_t
1252compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1253{
1254        struct file *file;
1255        ssize_t ret = -EBADF;
1256
1257        file = fget(fd);
1258        if (!file)
1259                return -EBADF;
1260
1261        if (!(file->f_mode & FMODE_READ))
1262                goto out;
1263
1264        ret = -EINVAL;
1265        if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
1266                goto out;
1267
1268        ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
1269
1270out:
1271        fput(file);
1272        return ret;
1273}
1274
1275asmlinkage ssize_t
1276compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
1277{
1278        struct file *file;
1279        ssize_t ret = -EBADF;
1280
1281        file = fget(fd);
1282        if (!file)
1283                return -EBADF;
1284        if (!(file->f_mode & FMODE_WRITE))
1285                goto out;
1286
1287        ret = -EINVAL;
1288        if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
1289                goto out;
1290
1291        ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
1292
1293out:
1294        fput(file);
1295        return ret;
1296}
1297
1298/*
1299 * compat_count() counts the number of arguments/envelopes. It is basically
1300 * a copy of count() from fs/exec.c, except that it works with 32 bit argv
1301 * and envp pointers.
1302 */
1303static int compat_count(compat_uptr_t __user *argv, int max)
1304{
1305        int i = 0;
1306
1307        if (argv != NULL) {
1308                for (;;) {
1309                        compat_uptr_t p;
1310
1311                        if (get_user(p, argv))
1312                                return -EFAULT;
1313                        if (!p)
1314                                break;
1315                        argv++;
1316                        if(++i > max)
1317                                return -E2BIG;
1318                }
1319        }
1320        return i;
1321}
1322
1323/*
1324 * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
1325 * except that it works with 32 bit argv and envp pointers.
1326 */
1327static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
1328                                struct linux_binprm *bprm)
1329{
1330        struct page *kmapped_page = NULL;
1331        char *kaddr = NULL;
1332        int ret;
1333
1334        while (argc-- > 0) {
1335                compat_uptr_t str;
1336                int len;
1337                unsigned long pos;
1338
1339                if (get_user(str, argv+argc) ||
1340                        !(len = strnlen_user(compat_ptr(str), bprm->p))) {
1341                        ret = -EFAULT;
1342                        goto out;
1343                }
1344
1345                if (bprm->p < len)  {
1346                        ret = -E2BIG;
1347                        goto out;
1348                }
1349
1350                bprm->p -= len;
1351                /* XXX: add architecture specific overflow check here. */
1352                pos = bprm->p;
1353
1354                while (len > 0) {
1355                        int i, new, err;
1356                        int offset, bytes_to_copy;
1357                        struct page *page;
1358
1359                        offset = pos % PAGE_SIZE;
1360                        i = pos/PAGE_SIZE;
1361                        page = bprm->page[i];
1362                        new = 0;
1363                        if (!page) {
1364                                page = alloc_page(GFP_HIGHUSER);
1365                                bprm->page[i] = page;
1366                                if (!page) {
1367                                        ret = -ENOMEM;
1368                                        goto out;
1369                                }
1370                                new = 1;
1371                        }
1372
1373                        if (page != kmapped_page) {
1374                                if (kmapped_page)
1375                                        kunmap(kmapped_page);
1376                                kmapped_page = page;
1377                                kaddr = kmap(kmapped_page);
1378                        }
1379                        if (new && offset)
1380                                memset(kaddr, 0, offset);
1381                        bytes_to_copy = PAGE_SIZE - offset;
1382                        if (bytes_to_copy > len) {
1383                                bytes_to_copy = len;
1384                                if (new)
1385                                        memset(kaddr+offset+len, 0,
1386                                                PAGE_SIZE-offset-len);
1387                        }
1388                        err = copy_from_user(kaddr+offset, compat_ptr(str),
1389                                                bytes_to_copy);
1390                        if (err) {
1391                                ret = -EFAULT;
1392                                goto out;
1393                        }
1394
1395                        pos += bytes_to_copy;
1396                        str += bytes_to_copy;
1397                        len -= bytes_to_copy;
1398                }
1399        }
1400        ret = 0;
1401out:
1402        if (kmapped_page)
1403                kunmap(kmapped_page);
1404        return ret;
1405}
1406
1407#ifdef CONFIG_MMU
1408
1409#define free_arg_pages(bprm) do { } while (0)
1410
1411#else
1412
1413static inline void free_arg_pages(struct linux_binprm *bprm)
1414{
1415        int i;
1416
1417        for (i = 0; i < MAX_ARG_PAGES; i++) {
1418                if (bprm->page[i])
1419                        __free_page(bprm->page[i]);
1420                bprm->page[i] = NULL;
1421        }
1422}
1423
1424#endif /* CONFIG_MMU */
1425
1426/*
1427 * compat_do_execve() is mostly a copy of do_execve(), with the exception
1428 * that it processes 32 bit argv and envp pointers.
1429 */
1430int compat_do_execve(char * filename,
1431        compat_uptr_t __user *argv,
1432        compat_uptr_t __user *envp,
1433        struct pt_regs * regs)
1434{
1435        struct linux_binprm *bprm;
1436        struct file *file;
1437        int retval;
1438        int i;
1439
1440        file = open_exec(filename);
1441
1442        retval = PTR_ERR(file);
1443        if (IS_ERR(file))
1444                return retval;
1445
1446        sched_exec();
1447
1448        retval = -ENOMEM;
1449        bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
1450        if (!bprm)
1451                goto out_ret;
1452        memset(bprm, 0, sizeof(*bprm));
1453
1454        bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
1455        bprm->file = file;
1456        bprm->filename = filename;
1457        bprm->interp = filename;
1458        bprm->mm = mm_alloc();
1459        if (!bprm->mm)
1460                goto out_file;
1461
1462        retval = init_new_context(current, bprm->mm);
1463        if (retval < 0)
1464                goto out_mm;
1465
1466        bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t));
1467        if ((retval = bprm->argc) < 0)
1468                goto out_mm;
1469
1470        bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t));
1471        if ((retval = bprm->envc) < 0)
1472                goto out_mm;
1473
1474        retval = security_bprm_alloc(bprm);
1475        if (retval)
1476                goto out;
1477
1478        retval = prepare_binprm(bprm);
1479        if (retval < 0)
1480                goto out;
1481
1482        retval = copy_strings_kernel(1, &bprm->filename, bprm);
1483        if (retval < 0)
1484                goto out;
1485
1486        bprm->exec = bprm->p;
1487        retval = compat_copy_strings(bprm->envc, envp, bprm);
1488        if (retval < 0)
1489                goto out;
1490
1491        retval = compat_copy_strings(bprm->argc, argv, bprm);
1492        if (retval < 0)
1493                goto out;
1494
1495        retval = search_binary_handler(bprm, regs);
1496        if (retval >= 0) {
1497                free_arg_pages(bprm);
1498
1499                /* execve success */
1500                security_bprm_free(bprm);
1501                kfree(bprm);
1502                return retval;
1503        }
1504
1505out:
1506        /* Something went wrong, return the inode and free the argument pages*/
1507        for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
1508                struct page * page = bprm->page[i];
1509                if (page)
1510                        __free_page(page);
1511        }
1512
1513        if (bprm->security)
1514                security_bprm_free(bprm);
1515
1516out_mm:
1517        if (bprm->mm)
1518                mmdrop(bprm->mm);
1519
1520out_file:
1521        if (bprm->file) {
1522                allow_write_access(bprm->file);
1523                fput(bprm->file);
1524        }
1525        kfree(bprm);
1526
1527out_ret:
1528        return retval;
1529}
1530
1531#define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
1532
1533#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
1534
1535/*
1536 * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
1537 * 64-bit unsigned longs.
1538 */
1539static inline
1540int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1541                        unsigned long *fdset)
1542{
1543        nr = ROUND_UP(nr, __COMPAT_NFDBITS);
1544        if (ufdset) {
1545                unsigned long odd;
1546
1547                if (verify_area(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
1548                        return -EFAULT;
1549
1550                odd = nr & 1UL;
1551                nr &= ~1UL;
1552                while (nr) {
1553                        unsigned long h, l;
1554                        __get_user(l, ufdset);
1555                        __get_user(h, ufdset+1);
1556                        ufdset += 2;
1557                        *fdset++ = h << 32 | l;
1558                        nr -= 2;
1559                }
1560                if (odd)
1561                        __get_user(*fdset, ufdset);
1562        } else {
1563                /* Tricky, must clear full unsigned long in the
1564                 * kernel fdset at the end, this makes sure that
1565                 * actually happens.
1566                 */
1567                memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
1568        }
1569        return 0;
1570}
1571
1572static inline
1573void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1574                        unsigned long *fdset)
1575{
1576        unsigned long odd;
1577        nr = ROUND_UP(nr, __COMPAT_NFDBITS);
1578
1579        if (!ufdset)
1580                return;
1581
1582        odd = nr & 1UL;
1583        nr &= ~1UL;
1584        while (nr) {
1585                unsigned long h, l;
1586                l = *fdset++;
1587                h = l >> 32;
1588                __put_user(l, ufdset);
1589                __put_user(h, ufdset+1);
1590                ufdset += 2;
1591                nr -= 2;
1592        }
1593        if (odd)
1594                __put_user(*fdset, ufdset);
1595}
1596
1597
1598/*
1599 * This is a virtual copy of sys_select from fs/select.c and probably
1600 * should be compared to it from time to time
1601 */
1602static void *select_bits_alloc(int size)
1603{
1604        return kmalloc(6 * size, GFP_KERNEL);
1605}
1606
1607static void select_bits_free(void *bits, int size)
1608{
1609        kfree(bits);
1610}
1611
1612/*
1613 * We can actually return ERESTARTSYS instead of EINTR, but I'd
1614 * like to be certain this leads to no problems. So I return
1615 * EINTR just for safety.
1616 *
1617 * Update: ERESTARTSYS breaks at least the xview clock binary, so
1618 * I'm trying ERESTARTNOHAND which restart only when you want to.
1619 */
1620#define MAX_SELECT_SECONDS \
1621        ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
1622
1623asmlinkage long
1624compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
1625                compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
1626{
1627        fd_set_bits fds;
1628        char *bits;
1629        long timeout;
1630        int ret, size, max_fdset;
1631
1632        timeout = MAX_SCHEDULE_TIMEOUT;
1633        if (tvp) {
1634                time_t sec, usec;
1635
1636                if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
1637                    || (ret = __get_user(sec, &tvp->tv_sec))
1638                    || (ret = __get_user(usec, &tvp->tv_usec)))
1639                        goto out_nofds;
1640
1641                ret = -EINVAL;
1642                if (sec < 0 || usec < 0)
1643                        goto out_nofds;
1644
1645                if ((unsigned long) sec < MAX_SELECT_SECONDS) {
1646                        timeout = ROUND_UP(usec, 1000000/HZ);
1647                        timeout += sec * (unsigned long) HZ;
1648                }
1649        }
1650
1651        ret = -EINVAL;
1652        if (n < 0)
1653                goto out_nofds;
1654
1655        /* max_fdset can increase, so grab it once to avoid race */
1656        max_fdset = current->files->max_fdset;
1657        if (n > max_fdset)
1658                n = max_fdset;
1659
1660        /*
1661         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
1662         * since we used fdset we need to allocate memory in units of
1663         * long-words.
1664         */
1665        ret = -ENOMEM;
1666        size = FDS_BYTES(n);
1667        bits = select_bits_alloc(size);
1668        if (!bits)
1669                goto out_nofds;
1670        fds.in      = (unsigned long *)  bits;
1671        fds.out     = (unsigned long *) (bits +   size);
1672        fds.ex      = (unsigned long *) (bits + 2*size);
1673        fds.res_in  = (unsigned long *) (bits + 3*size);
1674        fds.res_out = (unsigned long *) (bits + 4*size);
1675        fds.res_ex  = (unsigned long *) (bits + 5*size);
1676
1677        if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
1678            (ret = compat_get_fd_set(n, outp, fds.out)) ||
1679            (ret = compat_get_fd_set(n, exp, fds.ex)))
1680                goto out;
1681        zero_fd_set(n, fds.res_in);
1682        zero_fd_set(n, fds.res_out);
1683        zero_fd_set(n, fds.res_ex);
1684
1685        ret = do_select(n, &fds, &timeout);
1686
1687        if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
1688                time_t sec = 0, usec = 0;
1689                if (timeout) {
1690                        sec = timeout / HZ;
1691                        usec = timeout % HZ;
1692                        usec *= (1000000/HZ);
1693                }
1694                if (put_user(sec, &tvp->tv_sec) ||
1695                    put_user(usec, &tvp->tv_usec))
1696                        ret = -EFAULT;
1697        }
1698
1699        if (ret < 0)
1700                goto out;
1701        if (!ret) {
1702                ret = -ERESTARTNOHAND;
1703                if (signal_pending(current))
1704                        goto out;
1705                ret = 0;
1706        }
1707
1708        compat_set_fd_set(n, inp, fds.res_in);
1709        compat_set_fd_set(n, outp, fds.res_out);
1710        compat_set_fd_set(n, exp, fds.res_ex);
1711
1712out:
1713        select_bits_free(bits, size);
1714out_nofds:
1715        return ret;
1716}
1717
1718#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
1719/* Stuff for NFS server syscalls... */
1720struct compat_nfsctl_svc {
1721        u16                     svc32_port;
1722        s32                     svc32_nthreads;
1723};
1724
1725struct compat_nfsctl_client {
1726        s8                      cl32_ident[NFSCLNT_IDMAX+1];
1727        s32                     cl32_naddr;
1728        struct in_addr          cl32_addrlist[NFSCLNT_ADDRMAX];
1729        s32                     cl32_fhkeytype;
1730        s32                     cl32_fhkeylen;
1731        u8                      cl32_fhkey[NFSCLNT_KEYMAX];
1732};
1733
1734struct compat_nfsctl_export {
1735        char            ex32_client[NFSCLNT_IDMAX+1];
1736        char            ex32_path[NFS_MAXPATHLEN+1];
1737        compat_dev_t    ex32_dev;
1738        compat_ino_t    ex32_ino;
1739        compat_int_t    ex32_flags;
1740        compat_uid_t    ex32_anon_uid;
1741        compat_gid_t    ex32_anon_gid;
1742};
1743
1744struct compat_nfsctl_fdparm {
1745        struct sockaddr         gd32_addr;
1746        s8                      gd32_path[NFS_MAXPATHLEN+1];
1747        compat_int_t            gd32_version;
1748};
1749
1750struct compat_nfsctl_fsparm {
1751        struct sockaddr         gd32_addr;
1752        s8                      gd32_path[NFS_MAXPATHLEN+1];
1753        compat_int_t            gd32_maxlen;
1754};
1755
1756struct compat_nfsctl_arg {
1757        compat_int_t            ca32_version;   /* safeguard */
1758        union {
1759                struct compat_nfsctl_svc        u32_svc;
1760                struct compat_nfsctl_client     u32_client;
1761                struct compat_nfsctl_export     u32_export;
1762                struct compat_nfsctl_fdparm     u32_getfd;
1763                struct compat_nfsctl_fsparm     u32_getfs;
1764        } u;
1765#define ca32_svc        u.u32_svc
1766#define ca32_client     u.u32_client
1767#define ca32_export     u.u32_export
1768#define ca32_getfd      u.u32_getfd
1769#define ca32_getfs      u.u32_getfs
1770};
1771
1772union compat_nfsctl_res {
1773        __u8                    cr32_getfh[NFS_FHSIZE];
1774        struct knfsd_fh         cr32_getfs;
1775};
1776
1777static int compat_nfs_svc_trans(struct nfsctl_arg *karg,
1778                                struct compat_nfsctl_arg __user *arg)
1779{
1780        if(!access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc)) ||
1781                get_user(karg->ca_version, &arg->ca32_version) ||
1782                __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port) ||
1783                __get_user(karg->ca_svc.svc_nthreads,
1784                                &arg->ca32_svc.svc32_nthreads))
1785                return -EFAULT;
1786        return 0;
1787}
1788
1789static int compat_nfs_clnt_trans(struct nfsctl_arg *karg,
1790                                struct compat_nfsctl_arg __user *arg)
1791{
1792        if (!access_ok(VERIFY_READ, &arg->ca32_client,
1793                        sizeof(arg->ca32_client)) ||
1794                get_user(karg->ca_version, &arg->ca32_version) ||
1795                __copy_from_user(&karg->ca_client.cl_ident[0],
1796                                &arg->ca32_client.cl32_ident[0],
1797                                NFSCLNT_IDMAX) ||
1798                __get_user(karg->ca_client.cl_naddr,
1799                                &arg->ca32_client.cl32_naddr) ||
1800                __copy_from_user(&karg->ca_client.cl_addrlist[0],
1801                                &arg->ca32_client.cl32_addrlist[0],
1802                                (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)) ||
1803                __get_user(karg->ca_client.cl_fhkeytype,
1804                                &arg->ca32_client.cl32_fhkeytype) ||
1805                __get_user(karg->ca_client.cl_fhkeylen,
1806                                &arg->ca32_client.cl32_fhkeylen) ||
1807                __copy_from_user(&karg->ca_client.cl_fhkey[0],
1808                                &arg->ca32_client.cl32_fhkey[0],
1809                                NFSCLNT_KEYMAX))
1810                return -EFAULT;
1811
1812        return 0;
1813}
1814
1815static int compat_nfs_exp_trans(struct nfsctl_arg *karg,
1816                                struct compat_nfsctl_arg __user *arg)
1817{
1818        if (!access_ok(VERIFY_READ, &arg->ca32_export,
1819                                sizeof(arg->ca32_export)) ||
1820                get_user(karg->ca_version, &arg->ca32_version) ||
1821                __copy_from_user(&karg->ca_export.ex_client[0],
1822                                &arg->ca32_export.ex32_client[0],
1823                                NFSCLNT_IDMAX) ||
1824                __copy_from_user(&karg->ca_export.ex_path[0],
1825                                &arg->ca32_export.ex32_path[0],
1826                                NFS_MAXPATHLEN) ||
1827                __get_user(karg->ca_export.ex_dev,
1828                                &arg->ca32_export.ex32_dev) ||
1829                __get_user(karg->ca_export.ex_ino,
1830                                &arg->ca32_export.ex32_ino) ||
1831                __get_user(karg->ca_export.ex_flags,
1832                                &arg->ca32_export.ex32_flags) ||
1833                __get_user(karg->ca_export.ex_anon_uid,
1834                                &arg->ca32_export.ex32_anon_uid) ||
1835                __get_user(karg->ca_export.ex_anon_gid,
1836                                &arg->ca32_export.ex32_anon_gid))
1837                return -EFAULT;
1838        SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
1839        SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
1840
1841        return 0;
1842}
1843
1844static int compat_nfs_getfd_trans(struct nfsctl_arg *karg,
1845                                struct compat_nfsctl_arg __user *arg)
1846{
1847        if(!access_ok(VERIFY_READ, &arg->ca32_getfd, sizeof(arg->ca32_getfd)) ||
1848                get_user(karg->ca_version, &arg->ca32_version) ||
1849                __copy_from_user(&karg->ca_getfd.gd_addr,
1850                                &arg->ca32_getfd.gd32_addr,
1851                                (sizeof(struct sockaddr))) ||
1852                __copy_from_user(&karg->ca_getfd.gd_path,
1853                                &arg->ca32_getfd.gd32_path,
1854                                (NFS_MAXPATHLEN+1)) ||
1855                __get_user(karg->ca_getfd.gd_version,
1856                                &arg->ca32_getfd.gd32_version))
1857                return -EFAULT;
1858
1859        return 0;
1860}
1861
1862static int compat_nfs_getfs_trans(struct nfsctl_arg *karg,
1863                                struct compat_nfsctl_arg __user *arg)
1864{
1865        if (!access_ok(VERIFY_READ,&arg->ca32_getfs,sizeof(arg->ca32_getfs)) ||
1866                get_user(karg->ca_version, &arg->ca32_version) ||
1867                __copy_from_user(&karg->ca_getfs.gd_addr,
1868                                &arg->ca32_getfs.gd32_addr,
1869                                (sizeof(struct sockaddr))) ||
1870                __copy_from_user(&karg->ca_getfs.gd_path,
1871                                &arg->ca32_getfs.gd32_path,
1872                                (NFS_MAXPATHLEN+1)) ||
1873                __get_user(karg->ca_getfs.gd_maxlen,
1874                                &arg->ca32_getfs.gd32_maxlen))
1875                return -EFAULT;
1876
1877        return 0;
1878}
1879
1880/* This really doesn't need translations, we are only passing
1881 * back a union which contains opaque nfs file handle data.
1882 */
1883static int compat_nfs_getfh_res_trans(union nfsctl_res *kres,
1884                                union compat_nfsctl_res __user *res)
1885{
1886        int err;
1887
1888        err = copy_to_user(res, kres, sizeof(*res));
1889
1890        return (err) ? -EFAULT : 0;
1891}
1892
1893asmlinkage long compat_sys_nfsservctl(int cmd,
1894                                struct compat_nfsctl_arg __user *arg,
1895                                union compat_nfsctl_res __user *res)
1896{
1897        struct nfsctl_arg *karg;
1898        union nfsctl_res *kres;
1899        mm_segment_t oldfs;
1900        int err;
1901
1902        karg = kmalloc(sizeof(*karg), GFP_USER);
1903        kres = kmalloc(sizeof(*kres), GFP_USER);
1904        if(!karg || !kres) {
1905                err = -ENOMEM;
1906                goto done;
1907        }
1908
1909        switch(cmd) {
1910        case NFSCTL_SVC:
1911                err = compat_nfs_svc_trans(karg, arg);
1912                break;
1913
1914        case NFSCTL_ADDCLIENT:
1915                err = compat_nfs_clnt_trans(karg, arg);
1916                break;
1917
1918        case NFSCTL_DELCLIENT:
1919                err = compat_nfs_clnt_trans(karg, arg);
1920                break;
1921
1922        case NFSCTL_EXPORT:
1923        case NFSCTL_UNEXPORT:
1924                err = compat_nfs_exp_trans(karg, arg);
1925                break;
1926
1927        case NFSCTL_GETFD:
1928                err = compat_nfs_getfd_trans(karg, arg);
1929                break;
1930
1931        case NFSCTL_GETFS:
1932                err = compat_nfs_getfs_trans(karg, arg);
1933                break;
1934
1935        default:
1936                err = -EINVAL;
1937                break;
1938        }
1939
1940        if (err)
1941                goto done;
1942
1943        oldfs = get_fs();
1944        set_fs(KERNEL_DS);
1945        /* The __user pointer casts are valid because of the set_fs() */
1946        err = sys_nfsservctl(cmd, (void __user *) karg, (void __user *) kres);
1947        set_fs(oldfs);
1948
1949        if (err)
1950                goto done;
1951
1952        if((cmd == NFSCTL_GETFD) ||
1953           (cmd == NFSCTL_GETFS))
1954                err = compat_nfs_getfh_res_trans(kres, res);
1955
1956done:
1957        kfree(karg);
1958        kfree(kres);
1959        return err;
1960}
1961#else /* !NFSD */
1962long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
1963{
1964        return sys_ni_syscall();
1965}
1966#endif
1967