Blame view

net/compat.c 25.9 KB
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
   * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
   *
   * Copyright (C) 2000		VA Linux Co
   * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
   * Copyright (C) 1999 		Arun Sharma <arun.sharma@intel.com>
   * Copyright (C) 1997,1998 	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
   * Copyright (C) 2000		Hewlett-Packard Co.
   * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
11
   * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
   */
  
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
  #include <linux/types.h>
  #include <linux/file.h>
  #include <linux/icmpv6.h>
  #include <linux/socket.h>
  #include <linux/syscalls.h>
  #include <linux/filter.h>
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/security.h>
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
25
  #include <linux/audit.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
26
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  
  #include <net/scm.h>
  #include <net/sock.h>
dae502954   David L Stevens   ipv4/ipv6 compat:...
30
31
  #include <net/ip.h>
  #include <net/ipv6.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
32
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include <net/compat.h>
da1842849   Al Viro   net: switch impor...
34
35
36
37
  int get_compat_msghdr(struct msghdr *kmsg,
  		      struct compat_msghdr __user *umsg,
  		      struct sockaddr __user **save_addr,
  		      struct iovec **iov)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  {
5da028a8a   Al Viro   get_compat_msghdr...
39
  	struct compat_msghdr msg;
08adb7dab   Al Viro   fold verify_iovec...
40
  	ssize_t err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41

5da028a8a   Al Viro   get_compat_msghdr...
42
  	if (copy_from_user(&msg, umsg, sizeof(*umsg)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  		return -EFAULT;
91edd096e   Catalin Marinas   net: compat: Upda...
44

5da028a8a   Al Viro   get_compat_msghdr...
45
46
47
48
  	kmsg->msg_flags = msg.msg_flags;
  	kmsg->msg_namelen = msg.msg_namelen;
  
  	if (!msg.msg_name)
91edd096e   Catalin Marinas   net: compat: Upda...
49
50
51
52
  		kmsg->msg_namelen = 0;
  
  	if (kmsg->msg_namelen < 0)
  		return -EINVAL;
1661bf364   Dan Carpenter   net: heap overflo...
53
  	if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
db31c55a6   Dan Carpenter   net: clamp ->msg_...
54
  		kmsg->msg_namelen = sizeof(struct sockaddr_storage);
5da028a8a   Al Viro   get_compat_msghdr...
55
56
57
  
  	kmsg->msg_control = compat_ptr(msg.msg_control);
  	kmsg->msg_controllen = msg.msg_controllen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

08adb7dab   Al Viro   fold verify_iovec...
59
  	if (save_addr)
5da028a8a   Al Viro   get_compat_msghdr...
60
  		*save_addr = compat_ptr(msg.msg_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

5da028a8a   Al Viro   get_compat_msghdr...
62
  	if (msg.msg_name && kmsg->msg_namelen) {
08adb7dab   Al Viro   fold verify_iovec...
63
  		if (!save_addr) {
5da028a8a   Al Viro   get_compat_msghdr...
64
  			err = move_addr_to_kernel(compat_ptr(msg.msg_name),
08adb7dab   Al Viro   fold verify_iovec...
65
66
  						  kmsg->msg_namelen,
  						  kmsg->msg_name);
e71a4783a   Stephen Hemminger   [NET] core: white...
67
  			if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  				return err;
  		}
40eea803c   Andrey Ryabinin   net: sendmsg: fix...
70
  	} else {
08adb7dab   Al Viro   fold verify_iovec...
71
72
  		kmsg->msg_name = NULL;
  		kmsg->msg_namelen = 0;
40eea803c   Andrey Ryabinin   net: sendmsg: fix...
73
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

5da028a8a   Al Viro   get_compat_msghdr...
75
  	if (msg.msg_iovlen > UIO_MAXIOV)
084493200   Al Viro   {compat_,}verify_...
76
  		return -EMSGSIZE;
0345f9313   tadeusz.struk@intel.com   net: socket: add ...
77
  	kmsg->msg_iocb = NULL;
da1842849   Al Viro   net: switch impor...
78
  	return compat_import_iovec(save_addr ? READ : WRITE,
5da028a8a   Al Viro   get_compat_msghdr...
79
  				   compat_ptr(msg.msg_iov), msg.msg_iovlen,
da1842849   Al Viro   net: switch impor...
80
  				   UIO_FASTIOV, iov, &kmsg->msg_iter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
  }
  
  /* Bleech... */
  #define CMSG_COMPAT_ALIGN(len)	ALIGN((len), sizeof(s32))
  
  #define CMSG_COMPAT_DATA(cmsg)				\
1ff8cebf4   yuan linyu   scm: remove use C...
87
  	((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  #define CMSG_COMPAT_SPACE(len)				\
1ff8cebf4   yuan linyu   scm: remove use C...
89
  	(sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  #define CMSG_COMPAT_LEN(len)				\
1ff8cebf4   yuan linyu   scm: remove use C...
91
  	(sizeof(struct compat_cmsghdr) + (len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  
  #define CMSG_COMPAT_FIRSTHDR(msg)			\
  	(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ?	\
  	 (struct compat_cmsghdr __user *)((msg)->msg_control) :		\
  	 (struct compat_cmsghdr __user *)NULL)
  
  #define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
  	((ucmlen) >= sizeof(struct compat_cmsghdr) && \
  	 (ucmlen) <= (unsigned long) \
  	 ((mhdr)->msg_controllen - \
  	  ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
  
  static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg,
  		struct compat_cmsghdr __user *cmsg, int cmsg_len)
  {
  	char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
  	if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) >
  			msg->msg_controllen)
  		return NULL;
  	return (struct compat_cmsghdr __user *)ptr;
  }
  
  /* There is a lot of hair here because the alignment rules (and
   * thus placement) of cmsg headers and length are different for
   * 32-bit apps.  -DaveM
   */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
118
  int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
  			       unsigned char *stackbuf, int stackbuf_size)
  {
  	struct compat_cmsghdr __user *ucmsg;
  	struct cmsghdr *kcmsg, *kcmsg_base;
  	compat_size_t ucmlen;
  	__kernel_size_t kcmlen, tmp;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
125
  	int err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126

ac4340fc3   David S. Miller   net: Assert at bu...
127
128
  	BUILD_BUG_ON(sizeof(struct compat_cmsghdr) !=
  		     CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
  	kcmlen = 0;
  	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
  	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
e71a4783a   Stephen Hemminger   [NET] core: white...
132
133
  	while (ucmsg != NULL) {
  		if (get_user(ucmlen, &ucmsg->cmsg_len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
  			return -EFAULT;
  
  		/* Catch bogons. */
  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
  			return -EINVAL;
1ff8cebf4   yuan linyu   scm: remove use C...
139
  		tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
8920e8f94   Al Viro   [PATCH] Fix 32bit...
140
  		tmp = CMSG_ALIGN(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
  		kcmlen += tmp;
  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
  	}
e71a4783a   Stephen Hemminger   [NET] core: white...
144
  	if (kcmlen == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
  		return -EINVAL;
  
  	/* The kcmlen holds the 64-bit version of the control length.
  	 * It may not be modified as we do not stick it into the kmsg
  	 * until we have successfully copied over all of the data
  	 * from the user.
  	 */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
152
153
154
  	if (kcmlen > stackbuf_size)
  		kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
  	if (kcmsg == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
  		return -ENOBUFS;
  
  	/* Now copy them over neatly. */
  	memset(kcmsg, 0, kcmlen);
  	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
e71a4783a   Stephen Hemminger   [NET] core: white...
160
  	while (ucmsg != NULL) {
8920e8f94   Al Viro   [PATCH] Fix 32bit...
161
162
163
164
  		if (__get_user(ucmlen, &ucmsg->cmsg_len))
  			goto Efault;
  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
  			goto Einval;
1ff8cebf4   yuan linyu   scm: remove use C...
165
  		tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
8920e8f94   Al Viro   [PATCH] Fix 32bit...
166
167
  		if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
  			goto Einval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  		kcmsg->cmsg_len = tmp;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
169
170
171
172
173
  		tmp = CMSG_ALIGN(tmp);
  		if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
  		    __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
  		    copy_from_user(CMSG_DATA(kcmsg),
  				   CMSG_COMPAT_DATA(ucmsg),
1ff8cebf4   yuan linyu   scm: remove use C...
174
  				   (ucmlen - sizeof(*ucmsg))))
8920e8f94   Al Viro   [PATCH] Fix 32bit...
175
  			goto Efault;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  
  		/* Advance. */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
178
  		kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
  	}
c2a64bb9f   Meng Xu   net: compat: asse...
181
182
183
184
185
186
  	/*
  	 * check the length of messages copied in is the same as the
  	 * what we get from the first loop
  	 */
  	if ((char *)kcmsg - (char *)kcmsg_base != kcmlen)
  		goto Einval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
  	/* Ok, looks like we made it.  Hook it up and return success. */
  	kmsg->msg_control = kcmsg_base;
  	kmsg->msg_controllen = kcmlen;
  	return 0;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
191
192
193
194
195
196
  Einval:
  	err = -EINVAL;
  Efault:
  	if (kcmsg_base != (struct cmsghdr *)stackbuf)
  		sock_kfree_s(sk, kcmsg_base, kcmlen);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
  }
  
  int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
  	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
  	struct compat_cmsghdr cmhdr;
818810472   Jesper Juhl   net: Fix referenc...
203
204
  	struct compat_timeval ctv;
  	struct compat_timespec cts[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  	int cmlen;
e71a4783a   Stephen Hemminger   [NET] core: white...
206
  	if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
  		kmsg->msg_flags |= MSG_CTRUNC;
  		return 0; /* XXX: return error? check spec. */
  	}
ee4fa23c4   H. J. Lu   compat: Use COMPA...
210
  	if (!COMPAT_USE_64BIT_TIME) {
ee4fa23c4   H. J. Lu   compat: Use COMPA...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  		if (level == SOL_SOCKET && type == SCM_TIMESTAMP) {
  			struct timeval *tv = (struct timeval *)data;
  			ctv.tv_sec = tv->tv_sec;
  			ctv.tv_usec = tv->tv_usec;
  			data = &ctv;
  			len = sizeof(ctv);
  		}
  		if (level == SOL_SOCKET &&
  		    (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
  			int count = type == SCM_TIMESTAMPNS ? 1 : 3;
  			int i;
  			struct timespec *ts = (struct timespec *)data;
  			for (i = 0; i < count; i++) {
  				cts[i].tv_sec = ts[i].tv_sec;
  				cts[i].tv_nsec = ts[i].tv_nsec;
  			}
  			data = &cts;
  			len = sizeof(cts[0]) * count;
20d494735   Patrick Ohly   net: socket infra...
229
  		}
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
230
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  	cmlen = CMSG_COMPAT_LEN(len);
e71a4783a   Stephen Hemminger   [NET] core: white...
232
  	if (kmsg->msg_controllen < cmlen) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
237
238
  		kmsg->msg_flags |= MSG_CTRUNC;
  		cmlen = kmsg->msg_controllen;
  	}
  	cmhdr.cmsg_level = level;
  	cmhdr.cmsg_type = type;
  	cmhdr.cmsg_len = cmlen;
e71a4783a   Stephen Hemminger   [NET] core: white...
239
  	if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  		return -EFAULT;
e71a4783a   Stephen Hemminger   [NET] core: white...
241
  	if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  		return -EFAULT;
  	cmlen = CMSG_COMPAT_SPACE(len);
1ac70e7ad   Wei Yongjun   [NET]: Fix functi...
244
245
  	if (kmsg->msg_controllen < cmlen)
  		cmlen = kmsg->msg_controllen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	kmsg->msg_control += cmlen;
  	kmsg->msg_controllen -= cmlen;
  	return 0;
  }
  
  void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
  {
  	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
  	int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
  	int fdnum = scm->fp->count;
  	struct file **fp = scm->fp->fp;
  	int __user *cmfptr;
  	int err = 0, i;
  
  	if (fdnum < fdmax)
  		fdmax = fdnum;
  
  	for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) {
  		int new_fd;
  		err = security_file_receive(fp[i]);
  		if (err)
  			break;
4a19542e5   Ulrich Drepper   O_CLOEXEC for SCM...
268
269
  		err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
  					  ? O_CLOEXEC : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
278
  		if (err < 0)
  			break;
  		new_fd = err;
  		err = put_user(new_fd, cmfptr);
  		if (err) {
  			put_unused_fd(new_fd);
  			break;
  		}
  		/* Bump the usage count and install the file. */
cb0942b81   Al Viro   make get_file() r...
279
  		fd_install(new_fd, get_file(fp[i]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  	}
  
  	if (i > 0) {
  		int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
effee6a00   Miklos Szeredi   [NET]: File descr...
284
  		err = put_user(SOL_SOCKET, &cm->cmsg_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  		if (!err)
  			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
  		if (!err)
  			err = put_user(cmlen, &cm->cmsg_len);
  		if (!err) {
  			cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
  			kmsg->msg_control += cmlen;
  			kmsg->msg_controllen -= cmlen;
  		}
  	}
  	if (i < fdnum)
  		kmsg->msg_flags |= MSG_CTRUNC;
  
  	/*
  	 * All of the files that fit in the message have had their
  	 * usage counts incremented, so we just free the list.
  	 */
  	__scm_destroy(scm);
  }
719c44d34   Willem de Bruijn   packet: compat su...
304
305
  /* allocate a 64-bit sock_fprog on the user stack for duration of syscall. */
  struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
  {
  	struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
308
  	struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
f8f8a727e   Al Viro   get_compat_bpf_fp...
309
310
311
312
313
314
315
316
317
  	struct compat_sock_fprog f32;
  	struct sock_fprog f;
  
  	if (copy_from_user(&f32, fprog32, sizeof(*fprog32)))
  		return NULL;
  	memset(&f, 0, sizeof(f));
  	f.len = f32.len;
  	f.filter = compat_ptr(f32.filter);
  	if (copy_to_user(kfprog, &f, sizeof(struct sock_fprog)))
719c44d34   Willem de Bruijn   packet: compat su...
318
319
320
321
322
323
324
325
326
327
328
329
330
  		return NULL;
  
  	return kfprog;
  }
  EXPORT_SYMBOL_GPL(get_compat_bpf_fprog);
  
  static int do_set_attach_filter(struct socket *sock, int level, int optname,
  				char __user *optval, unsigned int optlen)
  {
  	struct sock_fprog __user *kfprog;
  
  	kfprog = get_compat_bpf_fprog(optval);
  	if (!kfprog)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  		return -EFAULT;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
332
  	return sock_setsockopt(sock, level, optname, (char __user *)kfprog,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  			      sizeof(struct sock_fprog));
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
335
  static int do_set_sock_timeout(struct socket *sock, int level,
b7058842c   David S. Miller   net: Make setsock...
336
  		int optname, char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  {
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
338
  	struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
344
345
346
347
348
349
350
  	struct timeval ktime;
  	mm_segment_t old_fs;
  	int err;
  
  	if (optlen < sizeof(*up))
  		return -EINVAL;
  	if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
  	    __get_user(ktime.tv_sec, &up->tv_sec) ||
  	    __get_user(ktime.tv_usec, &up->tv_usec))
  		return -EFAULT;
  	old_fs = get_fs();
  	set_fs(KERNEL_DS);
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
351
  	err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
  	set_fs(old_fs);
  
  	return err;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
356
  static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
357
  				char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
358
  {
195759884   Helge Deller   soreuseport: add ...
359
360
  	if (optname == SO_ATTACH_FILTER ||
  	    optname == SO_ATTACH_REUSEPORT_CBPF)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
361
362
  		return do_set_attach_filter(sock, level, optname,
  					    optval, optlen);
988bf7243   Lance Richardson   net: support comp...
363
364
  	if (!COMPAT_USE_64BIT_TIME &&
  	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
365
366
367
368
  		return do_set_sock_timeout(sock, level, optname, optval, optlen);
  
  	return sock_setsockopt(sock, level, optname, optval, optlen);
  }
73ee3eafd   Dominik Brodowski   net: socket: add ...
369
370
  static int __compat_sys_setsockopt(int fd, int level, int optname,
  				   char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
372
  	int err;
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
373
  	struct socket *sock = sockfd_lookup(fd, &err);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
374

c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
375
376
  	if (sock) {
  		err = security_socket_setsockopt(sock, level, optname);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  		if (err) {
  			sockfd_put(sock);
  			return err;
  		}
  
  		if (level == SOL_SOCKET)
  			err = compat_sock_setsockopt(sock, level,
  					optname, optval, optlen);
  		else if (sock->ops->compat_setsockopt)
  			err = sock->ops->compat_setsockopt(sock, level,
  					optname, optval, optlen);
  		else
  			err = sock->ops->setsockopt(sock, level,
  					optname, optval, optlen);
  		sockfd_put(sock);
  	}
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  }
73ee3eafd   Dominik Brodowski   net: socket: add ...
395
396
397
398
399
  COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
  		       char __user *, optval, unsigned int, optlen)
  {
  	return __compat_sys_setsockopt(fd, level, optname, optval, optlen);
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
400
  static int do_get_sock_timeout(struct socket *sock, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  		char __user *optval, int __user *optlen)
  {
  	struct compat_timeval __user *up;
  	struct timeval ktime;
  	mm_segment_t old_fs;
  	int len, err;
  
  	up = (struct compat_timeval __user *) optval;
  	if (get_user(len, optlen))
  		return -EFAULT;
  	if (len < sizeof(*up))
  		return -EINVAL;
  	len = sizeof(ktime);
  	old_fs = get_fs();
  	set_fs(KERNEL_DS);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
416
  	err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
421
422
423
424
425
426
427
  	set_fs(old_fs);
  
  	if (!err) {
  		if (put_user(sizeof(*up), optlen) ||
  		    !access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
  		    __put_user(ktime.tv_sec, &up->tv_sec) ||
  		    __put_user(ktime.tv_usec, &up->tv_usec))
  			err = -EFAULT;
  	}
  	return err;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
428
  static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
  				char __user *optval, int __user *optlen)
  {
988bf7243   Lance Richardson   net: support comp...
431
432
  	if (!COMPAT_USE_64BIT_TIME &&
  	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
433
434
  		return do_get_sock_timeout(sock, level, optname, optval, optlen);
  	return sock_getsockopt(sock, level, optname, optval, optlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  }
f0ac26144   Shaun Pereira   [NET]: socket tim...
436
437
  int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
  {
ee4fa23c4   H. J. Lu   compat: Use COMPA...
438
439
  	struct compat_timeval __user *ctv;
  	int err;
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
440
  	struct timeval tv;
f0ac26144   Shaun Pereira   [NET]: socket tim...
441

ee4fa23c4   H. J. Lu   compat: Use COMPA...
442
443
444
445
446
  	if (COMPAT_USE_64BIT_TIME)
  		return sock_get_timestamp(sk, userstamp);
  
  	ctv = (struct compat_timeval __user *) userstamp;
  	err = -ENOENT;
9dae34978   Yafang Shao   net: avoid unnece...
447
  	sock_enable_timestamp(sk, SOCK_TIMESTAMP);
60f05dddf   Deepa Dinamani   sock: Make sock->...
448
  	tv = ktime_to_timeval(sock_read_timestamp(sk));
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
449
  	if (tv.tv_sec == -1)
f0ac26144   Shaun Pereira   [NET]: socket tim...
450
  		return err;
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
451
  	if (tv.tv_sec == 0) {
60f05dddf   Deepa Dinamani   sock: Make sock->...
452
453
454
  		ktime_t kt = ktime_get_real();
  		sock_write_timestamp(sk, kt);
  		tv = ktime_to_timeval(kt);
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
455
456
457
458
  	}
  	err = 0;
  	if (put_user(tv.tv_sec, &ctv->tv_sec) ||
  			put_user(tv.tv_usec, &ctv->tv_usec))
f0ac26144   Shaun Pereira   [NET]: socket tim...
459
460
461
462
  		err = -EFAULT;
  	return err;
  }
  EXPORT_SYMBOL(compat_sock_get_timestamp);
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
463
464
  int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
  {
ee4fa23c4   H. J. Lu   compat: Use COMPA...
465
466
  	struct compat_timespec __user *ctv;
  	int err;
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
467
  	struct timespec ts;
ee4fa23c4   H. J. Lu   compat: Use COMPA...
468
469
470
471
472
  	if (COMPAT_USE_64BIT_TIME)
  		return sock_get_timestampns (sk, userstamp);
  
  	ctv = (struct compat_timespec __user *) userstamp;
  	err = -ENOENT;
9dae34978   Yafang Shao   net: avoid unnece...
473
  	sock_enable_timestamp(sk, SOCK_TIMESTAMP);
60f05dddf   Deepa Dinamani   sock: Make sock->...
474
  	ts = ktime_to_timespec(sock_read_timestamp(sk));
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
475
476
477
  	if (ts.tv_sec == -1)
  		return err;
  	if (ts.tv_sec == 0) {
60f05dddf   Deepa Dinamani   sock: Make sock->...
478
479
480
  		ktime_t kt = ktime_get_real();
  		sock_write_timestamp(sk, kt);
  		ts = ktime_to_timespec(kt);
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
481
482
483
484
485
486
487
488
  	}
  	err = 0;
  	if (put_user(ts.tv_sec, &ctv->tv_sec) ||
  			put_user(ts.tv_nsec, &ctv->tv_nsec))
  		err = -EFAULT;
  	return err;
  }
  EXPORT_SYMBOL(compat_sock_get_timestampns);
8770cf4a5   Dominik Brodowski   net: socket: add ...
489
490
491
  static int __compat_sys_getsockopt(int fd, int level, int optname,
  				   char __user *optval,
  				   int __user *optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
492
493
  {
  	int err;
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
494
  	struct socket *sock = sockfd_lookup(fd, &err);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
495

c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
496
497
  	if (sock) {
  		err = security_socket_getsockopt(sock, level, optname);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  		if (err) {
  			sockfd_put(sock);
  			return err;
  		}
  
  		if (level == SOL_SOCKET)
  			err = compat_sock_getsockopt(sock, level,
  					optname, optval, optlen);
  		else if (sock->ops->compat_getsockopt)
  			err = sock->ops->compat_getsockopt(sock, level,
  					optname, optval, optlen);
  		else
  			err = sock->ops->getsockopt(sock, level,
  					optname, optval, optlen);
  		sockfd_put(sock);
  	}
  	return err;
  }
dae502954   David L Stevens   ipv4/ipv6 compat:...
516

8770cf4a5   Dominik Brodowski   net: socket: add ...
517
518
519
520
521
  COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
  		       char __user *, optval, int __user *, optlen)
  {
  	return __compat_sys_getsockopt(fd, level, optname, optval, optlen);
  }
dae502954   David L Stevens   ipv4/ipv6 compat:...
522
523
524
  struct compat_group_req {
  	__u32				 gr_interface;
  	struct __kernel_sockaddr_storage gr_group
e099b2d9d   Ameen Ali   net: __aligned(si...
525
  		__aligned(4);
bc10502db   Eric Dumazet   net: use __packed...
526
  } __packed;
dae502954   David L Stevens   ipv4/ipv6 compat:...
527
528
529
530
  
  struct compat_group_source_req {
  	__u32				 gsr_interface;
  	struct __kernel_sockaddr_storage gsr_group
e099b2d9d   Ameen Ali   net: __aligned(si...
531
  		__aligned(4);
dae502954   David L Stevens   ipv4/ipv6 compat:...
532
  	struct __kernel_sockaddr_storage gsr_source
e099b2d9d   Ameen Ali   net: __aligned(si...
533
  		__aligned(4);
bc10502db   Eric Dumazet   net: use __packed...
534
  } __packed;
dae502954   David L Stevens   ipv4/ipv6 compat:...
535
536
537
538
  
  struct compat_group_filter {
  	__u32				 gf_interface;
  	struct __kernel_sockaddr_storage gf_group
e099b2d9d   Ameen Ali   net: __aligned(si...
539
  		__aligned(4);
dae502954   David L Stevens   ipv4/ipv6 compat:...
540
541
542
  	__u32				 gf_fmode;
  	__u32				 gf_numsrc;
  	struct __kernel_sockaddr_storage gf_slist[1]
e099b2d9d   Ameen Ali   net: __aligned(si...
543
  		__aligned(4);
bc10502db   Eric Dumazet   net: use __packed...
544
  } __packed;
dae502954   David L Stevens   ipv4/ipv6 compat:...
545

be666e0a1   David L Stevens   net: Several clea...
546
547
  #define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
  			sizeof(struct __kernel_sockaddr_storage))
dae502954   David L Stevens   ipv4/ipv6 compat:...
548
549
  
  int compat_mc_setsockopt(struct sock *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
550
  	char __user *optval, unsigned int optlen,
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
551
  	int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
dae502954   David L Stevens   ipv4/ipv6 compat:...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  {
  	char __user	*koptval = optval;
  	int		koptlen = optlen;
  
  	switch (optname) {
  	case MCAST_JOIN_GROUP:
  	case MCAST_LEAVE_GROUP:
  	{
  		struct compat_group_req __user *gr32 = (void *)optval;
  		struct group_req __user *kgr =
  			compat_alloc_user_space(sizeof(struct group_req));
  		u32 interface;
  
  		if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) ||
  		    !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) ||
  		    __get_user(interface, &gr32->gr_interface) ||
  		    __put_user(interface, &kgr->gr_interface) ||
  		    copy_in_user(&kgr->gr_group, &gr32->gr_group,
  				sizeof(kgr->gr_group)))
  			return -EFAULT;
  		koptval = (char __user *)kgr;
  		koptlen = sizeof(struct group_req);
  		break;
  	}
  	case MCAST_JOIN_SOURCE_GROUP:
  	case MCAST_LEAVE_SOURCE_GROUP:
  	case MCAST_BLOCK_SOURCE:
  	case MCAST_UNBLOCK_SOURCE:
  	{
  		struct compat_group_source_req __user *gsr32 = (void *)optval;
be666e0a1   David L Stevens   net: Several clea...
582
  		struct group_source_req __user *kgsr = compat_alloc_user_space(
dae502954   David L Stevens   ipv4/ipv6 compat:...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  			sizeof(struct group_source_req));
  		u32 interface;
  
  		if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) ||
  		    !access_ok(VERIFY_WRITE, kgsr,
  			sizeof(struct group_source_req)) ||
  		    __get_user(interface, &gsr32->gsr_interface) ||
  		    __put_user(interface, &kgsr->gsr_interface) ||
  		    copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group,
  				sizeof(kgsr->gsr_group)) ||
  		    copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source,
  				sizeof(kgsr->gsr_source)))
  			return -EFAULT;
  		koptval = (char __user *)kgsr;
  		koptlen = sizeof(struct group_source_req);
  		break;
  	}
  	case MCAST_MSFILTER:
  	{
  		struct compat_group_filter __user *gf32 = (void *)optval;
be666e0a1   David L Stevens   net: Several clea...
603
  		struct group_filter __user *kgf;
dae502954   David L Stevens   ipv4/ipv6 compat:...
604
  		u32 interface, fmode, numsrc;
be666e0a1   David L Stevens   net: Several clea...
605
  		if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
dae502954   David L Stevens   ipv4/ipv6 compat:...
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  		    __get_user(interface, &gf32->gf_interface) ||
  		    __get_user(fmode, &gf32->gf_fmode) ||
  		    __get_user(numsrc, &gf32->gf_numsrc))
  			return -EFAULT;
  		koptlen = optlen + sizeof(struct group_filter) -
  				sizeof(struct compat_group_filter);
  		if (koptlen < GROUP_FILTER_SIZE(numsrc))
  			return -EINVAL;
  		kgf = compat_alloc_user_space(koptlen);
  		if (!access_ok(VERIFY_WRITE, kgf, koptlen) ||
  		    __put_user(interface, &kgf->gf_interface) ||
  		    __put_user(fmode, &kgf->gf_fmode) ||
  		    __put_user(numsrc, &kgf->gf_numsrc) ||
  		    copy_in_user(&kgf->gf_group, &gf32->gf_group,
  				sizeof(kgf->gf_group)) ||
be666e0a1   David L Stevens   net: Several clea...
621
  		    (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
dae502954   David L Stevens   ipv4/ipv6 compat:...
622
623
624
625
626
627
628
629
630
631
632
  				numsrc * sizeof(kgf->gf_slist[0]))))
  			return -EFAULT;
  		koptval = (char __user *)kgf;
  		break;
  	}
  
  	default:
  		break;
  	}
  	return setsockopt(sock, level, optname, koptval, koptlen);
  }
dae502954   David L Stevens   ipv4/ipv6 compat:...
633
  EXPORT_SYMBOL(compat_mc_setsockopt);
42908c69f   David L Stevens   net: Add compat s...
634
635
  int compat_mc_getsockopt(struct sock *sock, int level, int optname,
  	char __user *optval, int __user *optlen,
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
636
  	int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
42908c69f   David L Stevens   net: Add compat s...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  {
  	struct compat_group_filter __user *gf32 = (void *)optval;
  	struct group_filter __user *kgf;
  	int __user	*koptlen;
  	u32 interface, fmode, numsrc;
  	int klen, ulen, err;
  
  	if (optname != MCAST_MSFILTER)
  		return getsockopt(sock, level, optname, optval, optlen);
  
  	koptlen = compat_alloc_user_space(sizeof(*koptlen));
  	if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
  	    __get_user(ulen, optlen))
  		return -EFAULT;
  
  	/* adjust len for pad */
  	klen = ulen + sizeof(*kgf) - sizeof(*gf32);
  
  	if (klen < GROUP_FILTER_SIZE(0))
  		return -EINVAL;
  
  	if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
  	    __put_user(klen, koptlen))
  		return -EFAULT;
  
  	/* have to allow space for previous compat_alloc_user_space, too */
  	kgf = compat_alloc_user_space(klen+sizeof(*optlen));
  
  	if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
  	    __get_user(interface, &gf32->gf_interface) ||
  	    __get_user(fmode, &gf32->gf_fmode) ||
  	    __get_user(numsrc, &gf32->gf_numsrc) ||
  	    __put_user(interface, &kgf->gf_interface) ||
  	    __put_user(fmode, &kgf->gf_fmode) ||
  	    __put_user(numsrc, &kgf->gf_numsrc) ||
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
672
  	    copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
42908c69f   David L Stevens   net: Add compat s...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  		return -EFAULT;
  
  	err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
  	if (err)
  		return err;
  
  	if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
  	    __get_user(klen, koptlen))
  		return -EFAULT;
  
  	ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
  
  	if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
  	    __put_user(ulen, optlen))
  		return -EFAULT;
  
  	if (!access_ok(VERIFY_READ, kgf, klen) ||
  	    !access_ok(VERIFY_WRITE, gf32, ulen) ||
  	    __get_user(interface, &kgf->gf_interface) ||
  	    __get_user(fmode, &kgf->gf_fmode) ||
  	    __get_user(numsrc, &kgf->gf_numsrc) ||
  	    __put_user(interface, &gf32->gf_interface) ||
  	    __put_user(fmode, &gf32->gf_fmode) ||
  	    __put_user(numsrc, &gf32->gf_numsrc))
  		return -EFAULT;
  	if (numsrc) {
  		int copylen;
  
  		klen -= GROUP_FILTER_SIZE(0);
  		copylen = numsrc * sizeof(gf32->gf_slist[0]);
  		if (copylen > klen)
  			copylen = klen;
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
705
  		if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
42908c69f   David L Stevens   net: Add compat s...
706
707
708
709
  			return -EFAULT;
  	}
  	return err;
  }
42908c69f   David L Stevens   net: Add compat s...
710
  EXPORT_SYMBOL(compat_mc_getsockopt);
dae502954   David L Stevens   ipv4/ipv6 compat:...
711

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  /* Argument list sizes for compat_sys_socketcall */
  #define AL(x) ((x) * sizeof(u32))
228e548e6   Anton Blanchard   net: Add sendmmsg...
714
  static unsigned char nas[21] = {
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
715
716
717
  	AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
  	AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
  	AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
228e548e6   Anton Blanchard   net: Add sendmmsg...
718
  	AL(4), AL(5), AL(4)
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
719
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  #undef AL
6df354653   Dominik Brodowski   net: socket: add ...
721
722
723
  static inline long __compat_sys_sendmsg(int fd,
  					struct compat_msghdr __user *msg,
  					unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
  {
e1834a329   Dominik Brodowski   net: socket: move...
725
726
  	return __sys_sendmsg(fd, (struct user_msghdr __user *)msg,
  			     flags | MSG_CMSG_COMPAT, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  }
6df354653   Dominik Brodowski   net: socket: add ...
728
729
730
731
732
733
734
735
736
  COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg,
  		       unsigned int, flags)
  {
  	return __compat_sys_sendmsg(fd, msg, flags);
  }
  
  static inline long __compat_sys_sendmmsg(int fd,
  					 struct compat_mmsghdr __user *mmsg,
  					 unsigned int vlen, unsigned int flags)
228e548e6   Anton Blanchard   net: Add sendmmsg...
737
738
  {
  	return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
e1834a329   Dominik Brodowski   net: socket: move...
739
  			      flags | MSG_CMSG_COMPAT, false);
228e548e6   Anton Blanchard   net: Add sendmmsg...
740
  }
6df354653   Dominik Brodowski   net: socket: add ...
741
742
743
744
745
746
747
748
749
  COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
  		       unsigned int, vlen, unsigned int, flags)
  {
  	return __compat_sys_sendmmsg(fd, mmsg, vlen, flags);
  }
  
  static inline long __compat_sys_recvmsg(int fd,
  					struct compat_msghdr __user *msg,
  					unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  {
e1834a329   Dominik Brodowski   net: socket: move...
751
752
  	return __sys_recvmsg(fd, (struct user_msghdr __user *)msg,
  			     flags | MSG_CMSG_COMPAT, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  }
6df354653   Dominik Brodowski   net: socket: add ...
754
755
756
757
758
  COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg,
  		       unsigned int, flags)
  {
  	return __compat_sys_recvmsg(fd, msg, flags);
  }
fd4e82f5b   Dominik Brodowski   net: socket: add ...
759
760
761
762
763
764
765
766
  static inline long __compat_sys_recvfrom(int fd, void __user *buf,
  					 compat_size_t len, unsigned int flags,
  					 struct sockaddr __user *addr,
  					 int __user *addrlen)
  {
  	return __sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr,
  			      addrlen);
  }
3a49a0f71   Heiko Carstens   net/compat: conve...
767
  COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
1dacc76d0   Johannes Berg   net/compat/wext: ...
768
  {
fd4e82f5b   Dominik Brodowski   net: socket: add ...
769
  	return __compat_sys_recvfrom(fd, buf, len, flags, NULL, NULL);
1dacc76d0   Johannes Berg   net/compat/wext: ...
770
  }
3a49a0f71   Heiko Carstens   net/compat: conve...
771
772
773
  COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
  		       unsigned int, flags, struct sockaddr __user *, addr,
  		       int __user *, addrlen)
1dacc76d0   Johannes Berg   net/compat/wext: ...
774
  {
fd4e82f5b   Dominik Brodowski   net: socket: add ...
775
  	return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen);
1dacc76d0   Johannes Berg   net/compat/wext: ...
776
  }
157b334aa   Dominik Brodowski   net: socket: add ...
777
778
779
  static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
  				 unsigned int vlen, unsigned int flags,
  				 struct compat_timespec __user *timeout)
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
780
781
782
  {
  	int datagrams;
  	struct timespec ktspec;
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
783

5b23136bc   Jean-Mickael Guerin   net: compat_sys_r...
784
785
786
  	if (timeout == NULL)
  		return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  				      flags | MSG_CMSG_COMPAT, NULL);
2def2ef2a   PaX Team   x86, x32: Correct...
787
  	if (compat_get_timespec(&ktspec, timeout))
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
788
789
790
791
  		return -EFAULT;
  
  	datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  				   flags | MSG_CMSG_COMPAT, &ktspec);
2def2ef2a   PaX Team   x86, x32: Correct...
792
  	if (datagrams > 0 && compat_put_timespec(&ktspec, timeout))
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
793
794
795
796
  		datagrams = -EFAULT;
  
  	return datagrams;
  }
157b334aa   Dominik Brodowski   net: socket: add ...
797
798
799
800
801
802
  COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
  		       unsigned int, vlen, unsigned int, flags,
  		       struct compat_timespec __user *, timeout)
  {
  	return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout);
  }
361d93c46   Heiko Carstens   net/compat: conve...
803
  COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  {
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
805
806
  	u32 a[AUDITSC_ARGS];
  	unsigned int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	u32 a0, a1;
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
808
  	int ret;
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
809

228e548e6   Anton Blanchard   net: Add sendmmsg...
810
  	if (call < SYS_SOCKET || call > SYS_SENDMMSG)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  		return -EINVAL;
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
812
813
814
815
816
  	len = nas[call];
  	if (len > sizeof(a))
  		return -EINVAL;
  
  	if (copy_from_user(a, args, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  		return -EFAULT;
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
818
819
820
821
  
  	ret = audit_socketcall_compat(len / sizeof(a[0]), a);
  	if (ret)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  	a0 = a[0];
  	a1 = a[1];
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
824

e71a4783a   Stephen Hemminger   [NET] core: white...
825
  	switch (call) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  	case SYS_SOCKET:
9d6a15c3f   Dominik Brodowski   net: socket: add ...
827
  		ret = __sys_socket(a0, a1, a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
  		break;
  	case SYS_BIND:
a87d35d87   Dominik Brodowski   net: socket: add ...
830
  		ret = __sys_bind(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
  		break;
  	case SYS_CONNECT:
1387c2c2f   Dominik Brodowski   net: socket: add ...
833
  		ret = __sys_connect(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
  		break;
  	case SYS_LISTEN:
25e290eed   Dominik Brodowski   net: socket: add ...
836
  		ret = __sys_listen(a0, a1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
  		break;
  	case SYS_ACCEPT:
4541e8056   Dominik Brodowski   net: socket: add ...
839
  		ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
  		break;
  	case SYS_GETSOCKNAME:
8882a107b   Dominik Brodowski   net: socket: add ...
842
  		ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
  		break;
  	case SYS_GETPEERNAME:
b21c8f838   Dominik Brodowski   net: socket: add ...
845
  		ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
  		break;
  	case SYS_SOCKETPAIR:
6debc8d83   Dominik Brodowski   net: socket: add ...
848
  		ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
850
  		break;
  	case SYS_SEND:
f3bf896b1   Dominik Brodowski   net: socket: repl...
851
  		ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
  		break;
  	case SYS_SENDTO:
211b634b7   Dominik Brodowski   net: socket: add ...
854
855
  		ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3],
  				   compat_ptr(a[4]), a[5]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  		break;
  	case SYS_RECV:
fd4e82f5b   Dominik Brodowski   net: socket: add ...
858
859
  		ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
  					    NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
  		break;
  	case SYS_RECVFROM:
fd4e82f5b   Dominik Brodowski   net: socket: add ...
862
863
864
  		ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
  					    compat_ptr(a[4]),
  					    compat_ptr(a[5]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  		break;
  	case SYS_SHUTDOWN:
005a1aeac   Dominik Brodowski   net: socket: add ...
867
  		ret = __sys_shutdown(a0, a1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
  		break;
  	case SYS_SETSOCKOPT:
73ee3eafd   Dominik Brodowski   net: socket: add ...
870
871
  		ret = __compat_sys_setsockopt(a0, a1, a[2],
  					      compat_ptr(a[3]), a[4]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
  		break;
  	case SYS_GETSOCKOPT:
8770cf4a5   Dominik Brodowski   net: socket: add ...
874
875
876
  		ret = __compat_sys_getsockopt(a0, a1, a[2],
  					      compat_ptr(a[3]),
  					      compat_ptr(a[4]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
  		break;
  	case SYS_SENDMSG:
6df354653   Dominik Brodowski   net: socket: add ...
879
  		ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
  		break;
228e548e6   Anton Blanchard   net: Add sendmmsg...
881
  	case SYS_SENDMMSG:
6df354653   Dominik Brodowski   net: socket: add ...
882
  		ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
228e548e6   Anton Blanchard   net: Add sendmmsg...
883
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
  	case SYS_RECVMSG:
6df354653   Dominik Brodowski   net: socket: add ...
885
  		ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  		break;
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
887
  	case SYS_RECVMMSG:
157b334aa   Dominik Brodowski   net: socket: add ...
888
889
  		ret = __compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
  					    compat_ptr(a[4]));
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
890
  		break;
de11defeb   Ulrich Drepper   reintroduce accept4
891
  	case SYS_ACCEPT4:
4541e8056   Dominik Brodowski   net: socket: add ...
892
  		ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
aaca0bdca   Ulrich Drepper   flag parameters: ...
893
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
  	default:
  		ret = -EINVAL;
  		break;
  	}
  	return ret;
  }