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@ucw.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/compat.h>
19 #include <linux/nfs4_mount.h>
20 #include <linux/syscalls.h>
21 #include <linux/slab.h>
22 #include <linux/uaccess.h>
23 #include "internal.h"
24 
25 struct compat_nfs_string {
26 	compat_uint_t len;
27 	compat_uptr_t data;
28 };
29 
compat_nfs_string(struct nfs_string * dst,struct compat_nfs_string * src)30 static inline void compat_nfs_string(struct nfs_string *dst,
31 				     struct compat_nfs_string *src)
32 {
33 	dst->data = compat_ptr(src->data);
34 	dst->len = src->len;
35 }
36 
37 struct compat_nfs4_mount_data_v1 {
38 	compat_int_t version;
39 	compat_int_t flags;
40 	compat_int_t rsize;
41 	compat_int_t wsize;
42 	compat_int_t timeo;
43 	compat_int_t retrans;
44 	compat_int_t acregmin;
45 	compat_int_t acregmax;
46 	compat_int_t acdirmin;
47 	compat_int_t acdirmax;
48 	struct compat_nfs_string client_addr;
49 	struct compat_nfs_string mnt_path;
50 	struct compat_nfs_string hostname;
51 	compat_uint_t host_addrlen;
52 	compat_uptr_t host_addr;
53 	compat_int_t proto;
54 	compat_int_t auth_flavourlen;
55 	compat_uptr_t auth_flavours;
56 };
57 
do_nfs4_super_data_conv(void * raw_data)58 static int do_nfs4_super_data_conv(void *raw_data)
59 {
60 	int version = *(compat_uint_t *) raw_data;
61 
62 	if (version == 1) {
63 		struct compat_nfs4_mount_data_v1 *raw = raw_data;
64 		struct nfs4_mount_data *real = raw_data;
65 
66 		/* copy the fields backwards */
67 		real->auth_flavours = compat_ptr(raw->auth_flavours);
68 		real->auth_flavourlen = raw->auth_flavourlen;
69 		real->proto = raw->proto;
70 		real->host_addr = compat_ptr(raw->host_addr);
71 		real->host_addrlen = raw->host_addrlen;
72 		compat_nfs_string(&real->hostname, &raw->hostname);
73 		compat_nfs_string(&real->mnt_path, &raw->mnt_path);
74 		compat_nfs_string(&real->client_addr, &raw->client_addr);
75 		real->acdirmax = raw->acdirmax;
76 		real->acdirmin = raw->acdirmin;
77 		real->acregmax = raw->acregmax;
78 		real->acregmin = raw->acregmin;
79 		real->retrans = raw->retrans;
80 		real->timeo = raw->timeo;
81 		real->wsize = raw->wsize;
82 		real->rsize = raw->rsize;
83 		real->flags = raw->flags;
84 		real->version = raw->version;
85 	}
86 
87 	return 0;
88 }
89 
90 #define NFS4_NAME	"nfs4"
91 
COMPAT_SYSCALL_DEFINE5(mount,const char __user *,dev_name,const char __user *,dir_name,const char __user *,type,compat_ulong_t,flags,const void __user *,data)92 COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
93 		       const char __user *, dir_name,
94 		       const char __user *, type, compat_ulong_t, flags,
95 		       const void __user *, data)
96 {
97 	char *kernel_type;
98 	void *options;
99 	char *kernel_dev;
100 	int retval;
101 
102 	kernel_type = copy_mount_string(type);
103 	retval = PTR_ERR(kernel_type);
104 	if (IS_ERR(kernel_type))
105 		goto out;
106 
107 	kernel_dev = copy_mount_string(dev_name);
108 	retval = PTR_ERR(kernel_dev);
109 	if (IS_ERR(kernel_dev))
110 		goto out1;
111 
112 	options = copy_mount_options(data);
113 	retval = PTR_ERR(options);
114 	if (IS_ERR(options))
115 		goto out2;
116 
117 	if (kernel_type && options) {
118 		if (!strcmp(kernel_type, NFS4_NAME)) {
119 			retval = -EINVAL;
120 			if (do_nfs4_super_data_conv(options))
121 				goto out3;
122 		}
123 	}
124 
125 	retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
126 
127  out3:
128 	kfree(options);
129  out2:
130 	kfree(kernel_dev);
131  out1:
132 	kfree(kernel_type);
133  out:
134 	return retval;
135 }
136