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 
22 struct compat_nfs_string {
23 	compat_uint_t len;
24 	compat_uptr_t data;
25 };
26 
compat_nfs_string(struct nfs_string * dst,struct compat_nfs_string * src)27 static 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 
34 struct 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 
do_nfs4_super_data_conv(void * raw_data)55 static 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 
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)89 COMPAT_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