vserver 2.0 rc7
[linux-2.6.git] / fs / compat.c
index e6c8fff..728cd83 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smb.h>
 #include <linux/smb_mount.h>
 #include <linux/ncp_mount.h>
+#include <linux/nfs4_mount.h>
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
@@ -131,7 +132,7 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
                 && (kbuf->f_ffree & 0xffffffff00000000ULL))
                        return -EOVERFLOW;
        }
-       if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
+       if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
            __put_user(kbuf->f_type, &ubuf->f_type) ||
            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
@@ -205,7 +206,7 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
                 && (kbuf->f_ffree & 0xffffffff00000000ULL))
                        return -EOVERFLOW;
        }
-       if (verify_area(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
+       if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf)) ||
            __put_user(kbuf->f_type, &ubuf->f_type) ||
            __put_user(kbuf->f_bsize, &ubuf->f_bsize) ||
            __put_user(kbuf->f_blocks, &ubuf->f_blocks) ||
@@ -806,10 +807,79 @@ static void *do_smb_super_data_conv(void *raw_data)
        return raw_data;
 }
 
+struct compat_nfs_string {
+       compat_uint_t len;
+       compat_uptr_t data;
+};
+
+static inline void compat_nfs_string(struct nfs_string *dst,
+                                    struct compat_nfs_string *src)
+{
+       dst->data = compat_ptr(src->data);
+       dst->len = src->len;
+}
+
+struct compat_nfs4_mount_data_v1 {
+       compat_int_t version;
+       compat_int_t flags;
+       compat_int_t rsize;
+       compat_int_t wsize;
+       compat_int_t timeo;
+       compat_int_t retrans;
+       compat_int_t acregmin;
+       compat_int_t acregmax;
+       compat_int_t acdirmin;
+       compat_int_t acdirmax;
+       struct compat_nfs_string client_addr;
+       struct compat_nfs_string mnt_path;
+       struct compat_nfs_string hostname;
+       compat_uint_t host_addrlen;
+       compat_uptr_t host_addr;
+       compat_int_t proto;
+       compat_int_t auth_flavourlen;
+       compat_uptr_t auth_flavours;
+};
+
+static int do_nfs4_super_data_conv(void *raw_data)
+{
+       int version = *(compat_uint_t *) raw_data;
+
+       if (version == 1) {
+               struct compat_nfs4_mount_data_v1 *raw = raw_data;
+               struct nfs4_mount_data *real = raw_data;
+
+               /* copy the fields backwards */
+               real->auth_flavours = compat_ptr(raw->auth_flavours);
+               real->auth_flavourlen = raw->auth_flavourlen;
+               real->proto = raw->proto;
+               real->host_addr = compat_ptr(raw->host_addr);
+               real->host_addrlen = raw->host_addrlen;
+               compat_nfs_string(&real->hostname, &raw->hostname);
+               compat_nfs_string(&real->mnt_path, &raw->mnt_path);
+               compat_nfs_string(&real->client_addr, &raw->client_addr);
+               real->acdirmax = raw->acdirmax;
+               real->acdirmin = raw->acdirmin;
+               real->acregmax = raw->acregmax;
+               real->acregmin = raw->acregmin;
+               real->retrans = raw->retrans;
+               real->timeo = raw->timeo;
+               real->wsize = raw->wsize;
+               real->rsize = raw->rsize;
+               real->flags = raw->flags;
+               real->version = raw->version;
+       }
+       else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 extern int copy_mount_options (const void __user *, unsigned long *);
 
 #define SMBFS_NAME      "smbfs"
 #define NCPFS_NAME      "ncpfs"
+#define NFS4_NAME      "nfs4"
 
 asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
                                 char __user * type, unsigned long flags,
@@ -845,6 +915,9 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
                        do_smb_super_data_conv((void *)data_page);
                } else if (!strcmp((char *)type_page, NCPFS_NAME)) {
                        do_ncp_super_data_conv((void *)data_page);
+               } else if (!strcmp((char *)type_page, NFS4_NAME)) {
+                       if (do_nfs4_super_data_conv((void *) data_page))
+                               goto out4;
                }
        }
 
@@ -853,6 +926,7 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
                        flags, (void*)data_page);
        unlock_kernel();
 
+ out4:
        free_page(data_page);
  out3:
        free_page(dev_page);
@@ -1152,7 +1226,7 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
                        goto out;
        }
        ret = -EFAULT;
-       if (verify_area(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
+       if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
                goto out;
 
        /*
@@ -1537,7 +1611,7 @@ int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
        if (ufdset) {
                unsigned long odd;
 
-               if (verify_area(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
+               if (!access_ok(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
                        return -EFAULT;
 
                odd = nr & 1UL;
@@ -1620,18 +1694,19 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
        fd_set_bits fds;
        char *bits;
        long timeout;
-       int ret, size, max_fdset;
+       int size, max_fdset, ret = -EINVAL;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
                time_t sec, usec;
 
-               if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-                   || (ret = __get_user(sec, &tvp->tv_sec))
-                   || (ret = __get_user(usec, &tvp->tv_usec)))
+               if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
+                   || __get_user(sec, &tvp->tv_sec)
+                   || __get_user(usec, &tvp->tv_usec)) {
+                       ret = -EFAULT;
                        goto out_nofds;
+               }
 
-               ret = -EINVAL;
                if (sec < 0 || usec < 0)
                        goto out_nofds;
 
@@ -1641,7 +1716,6 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp
                }
        }
 
-       ret = -EINVAL;
        if (n < 0)
                goto out_nofds;