linux/fs/compat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/fs/compat.c
   4 *
   5 *  Kernel compatibililty routines for e.g. 32 bit syscall support
   6 *  on 64 bit kernels.
   7 *
   8 *  Copyright (C) 2002       Stephen Rothwell, IBM Corporation
   9 *  Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
  10 *  Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
  11 *  Copyright (C) 2001,2002  Andi Kleen, SuSE Labs 
  12 *  Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
  13 */
  14
  15#include <linux/compat.h>
  16#include <linux/nfs4_mount.h>
  17#include <linux/syscalls.h>
  18#include <linux/slab.h>
  19#include <linux/uaccess.h>
  20#include "internal.h"
  21
  22struct compat_nfs_string {
  23        compat_uint_t len;
  24        compat_uptr_t data;
  25};
  26
  27static inline void compat_nfs_string(struct nfs_string *dst,
  28                                     struct compat_nfs_string *src)
  29{
  30        dst->data = compat_ptr(src->data);
  31        dst->len = src->len;
  32}
  33
  34struct compat_nfs4_mount_data_v1 {
  35        compat_int_t version;
  36        compat_int_t flags;
  37        compat_int_t rsize;
  38        compat_int_t wsize;
  39        compat_int_t timeo;
  40        compat_int_t retrans;
  41        compat_int_t acregmin;
  42        compat_int_t acregmax;
  43        compat_int_t acdirmin;
  44        compat_int_t acdirmax;
  45        struct compat_nfs_string client_addr;
  46        struct compat_nfs_string mnt_path;
  47        struct compat_nfs_string hostname;
  48        compat_uint_t host_addrlen;
  49        compat_uptr_t host_addr;
  50        compat_int_t proto;
  51        compat_int_t auth_flavourlen;
  52        compat_uptr_t auth_flavours;
  53};
  54
  55static int do_nfs4_super_data_conv(void *raw_data)
  56{
  57        int version = *(compat_uint_t *) raw_data;
  58
  59        if (version == 1) {
  60                struct compat_nfs4_mount_data_v1 *raw = raw_data;
  61                struct nfs4_mount_data *real = raw_data;
  62
  63                /* copy the fields backwards */
  64                real->auth_flavours = compat_ptr(raw->auth_flavours);
  65                real->auth_flavourlen = raw->auth_flavourlen;
  66                real->proto = raw->proto;
  67                real->host_addr = compat_ptr(raw->host_addr);
  68                real->host_addrlen = raw->host_addrlen;
  69                compat_nfs_string(&real->hostname, &raw->hostname);
  70                compat_nfs_string(&real->mnt_path, &raw->mnt_path);
  71                compat_nfs_string(&real->client_addr, &raw->client_addr);
  72                real->acdirmax = raw->acdirmax;
  73                real->acdirmin = raw->acdirmin;
  74                real->acregmax = raw->acregmax;
  75                real->acregmin = raw->acregmin;
  76                real->retrans = raw->retrans;
  77                real->timeo = raw->timeo;
  78                real->wsize = raw->wsize;
  79                real->rsize = raw->rsize;
  80                real->flags = raw->flags;
  81                real->version = raw->version;
  82        }
  83
  84        return 0;
  85}
  86
  87#define NFS4_NAME       "nfs4"
  88
  89COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
  90                       const char __user *, dir_name,
  91                       const char __user *, type, compat_ulong_t, flags,
  92                       const void __user *, data)
  93{
  94        char *kernel_type;
  95        void *options;
  96        char *kernel_dev;
  97        int retval;
  98
  99        kernel_type = copy_mount_string(type);
 100        retval = PTR_ERR(kernel_type);
 101        if (IS_ERR(kernel_type))
 102                goto out;
 103
 104        kernel_dev = copy_mount_string(dev_name);
 105        retval = PTR_ERR(kernel_dev);
 106        if (IS_ERR(kernel_dev))
 107                goto out1;
 108
 109        options = copy_mount_options(data);
 110        retval = PTR_ERR(options);
 111        if (IS_ERR(options))
 112                goto out2;
 113
 114        if (kernel_type && options) {
 115                if (!strcmp(kernel_type, NFS4_NAME)) {
 116                        retval = -EINVAL;
 117                        if (do_nfs4_super_data_conv(options))
 118                                goto out3;
 119                }
 120        }
 121
 122        retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
 123
 124 out3:
 125        kfree(options);
 126 out2:
 127        kfree(kernel_dev);
 128 out1:
 129        kfree(kernel_type);
 130 out:
 131        return retval;
 132}
 133