Blame view

net/compat.c 24.3 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>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
25
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
  
  #include <net/scm.h>
  #include <net/sock.h>
dae502954   David L Stevens   ipv4/ipv6 compat:...
29
30
  #include <net/ip.h>
  #include <net/ipv6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include <asm/uaccess.h>
  #include <net/compat.h>
da1842849   Al Viro   net: switch impor...
33
34
35
36
  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
37
  {
08adb7dab   Al Viro   fold verify_iovec...
38
  	compat_uptr_t uaddr, uiov, tmp3;
c0371da60   Al Viro   put iov_iter into...
39
  	compat_size_t nr_segs;
08adb7dab   Al Viro   fold verify_iovec...
40
  	ssize_t err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  
  	if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) ||
08adb7dab   Al Viro   fold verify_iovec...
43
  	    __get_user(uaddr, &umsg->msg_name) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  	    __get_user(kmsg->msg_namelen, &umsg->msg_namelen) ||
08adb7dab   Al Viro   fold verify_iovec...
45
  	    __get_user(uiov, &umsg->msg_iov) ||
c0371da60   Al Viro   put iov_iter into...
46
  	    __get_user(nr_segs, &umsg->msg_iovlen) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
  	    __get_user(tmp3, &umsg->msg_control) ||
  	    __get_user(kmsg->msg_controllen, &umsg->msg_controllen) ||
  	    __get_user(kmsg->msg_flags, &umsg->msg_flags))
  		return -EFAULT;
91edd096e   Catalin Marinas   net: compat: Upda...
51
52
53
54
55
56
  
  	if (!uaddr)
  		kmsg->msg_namelen = 0;
  
  	if (kmsg->msg_namelen < 0)
  		return -EINVAL;
1661bf364   Dan Carpenter   net: heap overflo...
57
  	if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
db31c55a6   Dan Carpenter   net: clamp ->msg_...
58
  		kmsg->msg_namelen = sizeof(struct sockaddr_storage);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  	kmsg->msg_control = compat_ptr(tmp3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

08adb7dab   Al Viro   fold verify_iovec...
61
62
  	if (save_addr)
  		*save_addr = compat_ptr(uaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

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

c0371da60   Al Viro   put iov_iter into...
77
  	if (nr_segs > UIO_MAXIOV)
084493200   Al Viro   {compat_,}verify_...
78
  		return -EMSGSIZE;
0345f9313   tadeusz.struk@intel.com   net: socket: add ...
79
  	kmsg->msg_iocb = NULL;
da1842849   Al Viro   net: switch impor...
80
81
82
  	return compat_import_iovec(save_addr ? READ : WRITE,
  				   compat_ptr(uiov), nr_segs,
  				   UIO_FASTIOV, iov, &kmsg->msg_iter);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
91
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
118
119
  }
  
  /* Bleech... */
  #define CMSG_COMPAT_ALIGN(len)	ALIGN((len), sizeof(s32))
  
  #define CMSG_COMPAT_DATA(cmsg)				\
  	((void __user *)((char __user *)(cmsg) + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))))
  #define CMSG_COMPAT_SPACE(len)				\
  	(CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + CMSG_COMPAT_ALIGN(len))
  #define CMSG_COMPAT_LEN(len)				\
  	(CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) + (len))
  
  #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...
120
  int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
  			       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...
127
  	int err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
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
139
140
141
  			return -EFAULT;
  
  		/* Catch bogons. */
  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
  			return -EINVAL;
  
  		tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
  		       CMSG_ALIGN(sizeof(struct cmsghdr)));
8920e8f94   Al Viro   [PATCH] Fix 32bit...
142
  		tmp = CMSG_ALIGN(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
  		kcmlen += tmp;
  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
  	}
e71a4783a   Stephen Hemminger   [NET] core: white...
146
  	if (kcmlen == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
  		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...
154
155
156
  	if (kcmlen > stackbuf_size)
  		kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
  	if (kcmsg == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
  		return -ENOBUFS;
  
  	/* Now copy them over neatly. */
  	memset(kcmsg, 0, kcmlen);
  	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
e71a4783a   Stephen Hemminger   [NET] core: white...
162
  	while (ucmsg != NULL) {
8920e8f94   Al Viro   [PATCH] Fix 32bit...
163
164
165
166
  		if (__get_user(ucmlen, &ucmsg->cmsg_len))
  			goto Efault;
  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
  			goto Einval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
  		tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) +
  		       CMSG_ALIGN(sizeof(struct cmsghdr)));
8920e8f94   Al Viro   [PATCH] Fix 32bit...
169
170
  		if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
  			goto Einval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		kcmsg->cmsg_len = tmp;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
172
173
174
175
176
177
178
  		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),
  				   (ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg)))))
  			goto Efault;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  
  		/* Advance. */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
181
  		kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
187
188
  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
  	}
  
  	/* 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...
189
190
191
192
193
194
  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
195
196
197
198
  }
  
  int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
  	struct compat_cmsghdr cmhdr;
818810472   Jesper Juhl   net: Fix referenc...
201
202
  	struct compat_timeval ctv;
  	struct compat_timespec cts[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	int cmlen;
e71a4783a   Stephen Hemminger   [NET] core: white...
204
  	if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
  		kmsg->msg_flags |= MSG_CTRUNC;
  		return 0; /* XXX: return error? check spec. */
  	}
ee4fa23c4   H. J. Lu   compat: Use COMPA...
208
  	if (!COMPAT_USE_64BIT_TIME) {
ee4fa23c4   H. J. Lu   compat: Use COMPA...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  		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...
227
  		}
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
228
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  	cmlen = CMSG_COMPAT_LEN(len);
e71a4783a   Stephen Hemminger   [NET] core: white...
230
  	if (kmsg->msg_controllen < cmlen) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
235
236
  		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...
237
  	if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  		return -EFAULT;
e71a4783a   Stephen Hemminger   [NET] core: white...
239
  	if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  		return -EFAULT;
  	cmlen = CMSG_COMPAT_SPACE(len);
1ac70e7ad   Wei Yongjun   [NET]: Fix functi...
242
243
  	if (kmsg->msg_controllen < cmlen)
  		cmlen = kmsg->msg_controllen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  	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...
266
267
  		err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
  					  ? O_CLOEXEC : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
274
275
276
  		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...
277
  		fd_install(new_fd, get_file(fp[i]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
  	}
  
  	if (i > 0) {
  		int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
effee6a00   Miklos Szeredi   [NET]: File descr...
282
  		err = put_user(SOL_SOCKET, &cm->cmsg_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  		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...
302
303
  /* 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
304
305
  {
  	struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
306
  	struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
  	compat_uptr_t ptr;
  	u16 len;
  
  	if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
  	    !access_ok(VERIFY_WRITE, kfprog, sizeof(struct sock_fprog)) ||
  	    __get_user(len, &fprog32->len) ||
  	    __get_user(ptr, &fprog32->filter) ||
  	    __put_user(len, &kfprog->len) ||
  	    __put_user(compat_ptr(ptr), &kfprog->filter))
719c44d34   Willem de Bruijn   packet: compat su...
316
317
318
319
320
321
322
323
324
325
326
327
328
  		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
329
  		return -EFAULT;
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
330
  	return sock_setsockopt(sock, level, optname, (char __user *)kfprog,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
  			      sizeof(struct sock_fprog));
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
333
  static int do_set_sock_timeout(struct socket *sock, int level,
b7058842c   David S. Miller   net: Make setsock...
334
  		int optname, char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  {
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
336
  	struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
342
343
344
345
346
347
348
  	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...
349
  	err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
  	set_fs(old_fs);
  
  	return err;
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
354
  static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
355
  				char __user *optval, unsigned int optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
356
  {
195759884   Helge Deller   soreuseport: add ...
357
358
  	if (optname == SO_ATTACH_FILTER ||
  	    optname == SO_ATTACH_REUSEPORT_CBPF)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
359
360
361
362
363
364
365
  		return do_set_attach_filter(sock, level, optname,
  					    optval, optlen);
  	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
  		return do_set_sock_timeout(sock, level, optname, optval, optlen);
  
  	return sock_setsockopt(sock, level, optname, optval, optlen);
  }
361d93c46   Heiko Carstens   net/compat: conve...
366
367
  COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
  		       char __user *, optval, unsigned int, optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
369
  	int err;
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
370
  	struct socket *sock = sockfd_lookup(fd, &err);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
371

c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
372
373
  	if (sock) {
  		err = security_socket_setsockopt(sock, level, optname);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  		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
391
  }
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
392
  static int do_get_sock_timeout(struct socket *sock, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  		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...
408
  	err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
414
415
416
417
418
419
  	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...
420
  static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
  				char __user *optval, int __user *optlen)
  {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
423
424
425
  	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
  		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
426
  }
f0ac26144   Shaun Pereira   [NET]: socket tim...
427
428
  int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
  {
ee4fa23c4   H. J. Lu   compat: Use COMPA...
429
430
  	struct compat_timeval __user *ctv;
  	int err;
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
431
  	struct timeval tv;
f0ac26144   Shaun Pereira   [NET]: socket tim...
432

ee4fa23c4   H. J. Lu   compat: Use COMPA...
433
434
435
436
437
  	if (COMPAT_USE_64BIT_TIME)
  		return sock_get_timestamp(sk, userstamp);
  
  	ctv = (struct compat_timeval __user *) userstamp;
  	err = -ENOENT;
f0ac26144   Shaun Pereira   [NET]: socket tim...
438
  	if (!sock_flag(sk, SOCK_TIMESTAMP))
20d494735   Patrick Ohly   net: socket infra...
439
  		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
440
441
  	tv = ktime_to_timeval(sk->sk_stamp);
  	if (tv.tv_sec == -1)
f0ac26144   Shaun Pereira   [NET]: socket tim...
442
  		return err;
b7aa0bf70   Eric Dumazet   [NET]: convert ne...
443
444
445
446
447
448
449
  	if (tv.tv_sec == 0) {
  		sk->sk_stamp = ktime_get_real();
  		tv = ktime_to_timeval(sk->sk_stamp);
  	}
  	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...
450
451
452
453
  		err = -EFAULT;
  	return err;
  }
  EXPORT_SYMBOL(compat_sock_get_timestamp);
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
454
455
  int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
  {
ee4fa23c4   H. J. Lu   compat: Use COMPA...
456
457
  	struct compat_timespec __user *ctv;
  	int err;
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
458
  	struct timespec ts;
ee4fa23c4   H. J. Lu   compat: Use COMPA...
459
460
461
462
463
  	if (COMPAT_USE_64BIT_TIME)
  		return sock_get_timestampns (sk, userstamp);
  
  	ctv = (struct compat_timespec __user *) userstamp;
  	err = -ENOENT;
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
464
  	if (!sock_flag(sk, SOCK_TIMESTAMP))
20d494735   Patrick Ohly   net: socket infra...
465
  		sock_enable_timestamp(sk, SOCK_TIMESTAMP);
ae40eb1ef   Eric Dumazet   [NET]: Introduce ...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  	ts = ktime_to_timespec(sk->sk_stamp);
  	if (ts.tv_sec == -1)
  		return err;
  	if (ts.tv_sec == 0) {
  		sk->sk_stamp = ktime_get_real();
  		ts = ktime_to_timespec(sk->sk_stamp);
  	}
  	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);
361d93c46   Heiko Carstens   net/compat: conve...
480
481
  COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
  		       char __user *, optval, int __user *, optlen)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
482
483
  {
  	int err;
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
484
  	struct socket *sock = sockfd_lookup(fd, &err);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
485

c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
486
487
  	if (sock) {
  		err = security_socket_getsockopt(sock, level, optname);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  		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:...
506
507
508
509
  
  struct compat_group_req {
  	__u32				 gr_interface;
  	struct __kernel_sockaddr_storage gr_group
e099b2d9d   Ameen Ali   net: __aligned(si...
510
  		__aligned(4);
bc10502db   Eric Dumazet   net: use __packed...
511
  } __packed;
dae502954   David L Stevens   ipv4/ipv6 compat:...
512
513
514
515
  
  struct compat_group_source_req {
  	__u32				 gsr_interface;
  	struct __kernel_sockaddr_storage gsr_group
e099b2d9d   Ameen Ali   net: __aligned(si...
516
  		__aligned(4);
dae502954   David L Stevens   ipv4/ipv6 compat:...
517
  	struct __kernel_sockaddr_storage gsr_source
e099b2d9d   Ameen Ali   net: __aligned(si...
518
  		__aligned(4);
bc10502db   Eric Dumazet   net: use __packed...
519
  } __packed;
dae502954   David L Stevens   ipv4/ipv6 compat:...
520
521
522
523
  
  struct compat_group_filter {
  	__u32				 gf_interface;
  	struct __kernel_sockaddr_storage gf_group
e099b2d9d   Ameen Ali   net: __aligned(si...
524
  		__aligned(4);
dae502954   David L Stevens   ipv4/ipv6 compat:...
525
526
527
  	__u32				 gf_fmode;
  	__u32				 gf_numsrc;
  	struct __kernel_sockaddr_storage gf_slist[1]
e099b2d9d   Ameen Ali   net: __aligned(si...
528
  		__aligned(4);
bc10502db   Eric Dumazet   net: use __packed...
529
  } __packed;
dae502954   David L Stevens   ipv4/ipv6 compat:...
530

be666e0a1   David L Stevens   net: Several clea...
531
532
  #define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
  			sizeof(struct __kernel_sockaddr_storage))
dae502954   David L Stevens   ipv4/ipv6 compat:...
533
534
  
  int compat_mc_setsockopt(struct sock *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
535
  	char __user *optval, unsigned int optlen,
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
536
  	int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
dae502954   David L Stevens   ipv4/ipv6 compat:...
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  {
  	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...
567
  		struct group_source_req __user *kgsr = compat_alloc_user_space(
dae502954   David L Stevens   ipv4/ipv6 compat:...
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  			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...
588
  		struct group_filter __user *kgf;
dae502954   David L Stevens   ipv4/ipv6 compat:...
589
  		u32 interface, fmode, numsrc;
be666e0a1   David L Stevens   net: Several clea...
590
  		if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
dae502954   David L Stevens   ipv4/ipv6 compat:...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  		    __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...
606
  		    (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
dae502954   David L Stevens   ipv4/ipv6 compat:...
607
608
609
610
611
612
613
614
615
616
617
  				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:...
618
  EXPORT_SYMBOL(compat_mc_setsockopt);
42908c69f   David L Stevens   net: Add compat s...
619
620
  int compat_mc_getsockopt(struct sock *sock, int level, int optname,
  	char __user *optval, int __user *optlen,
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
621
  	int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
42908c69f   David L Stevens   net: Add compat s...
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
  {
  	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...
657
  	    copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
42908c69f   David L Stevens   net: Add compat s...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
  		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...
690
  		if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
42908c69f   David L Stevens   net: Add compat s...
691
692
693
694
  			return -EFAULT;
  	}
  	return err;
  }
42908c69f   David L Stevens   net: Add compat s...
695
  EXPORT_SYMBOL(compat_mc_getsockopt);
dae502954   David L Stevens   ipv4/ipv6 compat:...
696

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
  /* Argument list sizes for compat_sys_socketcall */
  #define AL(x) ((x) * sizeof(u32))
228e548e6   Anton Blanchard   net: Add sendmmsg...
699
  static unsigned char nas[21] = {
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
700
701
702
  	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...
703
  	AL(4), AL(5), AL(4)
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
704
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  #undef AL
361d93c46   Heiko Carstens   net/compat: conve...
706
  COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
  {
666547ff5   Al Viro   separate kernel- ...
708
  	return __sys_sendmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
  }
361d93c46   Heiko Carstens   net/compat: conve...
710
711
  COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
  		       unsigned int, vlen, unsigned int, flags)
228e548e6   Anton Blanchard   net: Add sendmmsg...
712
713
714
715
  {
  	return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  			      flags | MSG_CMSG_COMPAT);
  }
361d93c46   Heiko Carstens   net/compat: conve...
716
  COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg, unsigned int, flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  {
666547ff5   Al Viro   separate kernel- ...
718
  	return __sys_recvmsg(fd, (struct user_msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  }
3a49a0f71   Heiko Carstens   net/compat: conve...
720
  COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
1dacc76d0   Johannes Berg   net/compat/wext: ...
721
722
723
  {
  	return sys_recv(fd, buf, len, flags | MSG_CMSG_COMPAT);
  }
3a49a0f71   Heiko Carstens   net/compat: conve...
724
725
726
  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: ...
727
728
729
  {
  	return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
  }
361d93c46   Heiko Carstens   net/compat: conve...
730
731
732
  COMPAT_SYSCALL_DEFINE5(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...
733
734
735
  {
  	int datagrams;
  	struct timespec ktspec;
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
736

5b23136bc   Jean-Mickael Guerin   net: compat_sys_r...
737
738
739
  	if (timeout == NULL)
  		return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  				      flags | MSG_CMSG_COMPAT, NULL);
2def2ef2a   PaX Team   x86, x32: Correct...
740
  	if (compat_get_timespec(&ktspec, timeout))
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
741
742
743
744
  		return -EFAULT;
  
  	datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  				   flags | MSG_CMSG_COMPAT, &ktspec);
2def2ef2a   PaX Team   x86, x32: Correct...
745
  	if (datagrams > 0 && compat_put_timespec(&ktspec, timeout))
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
746
747
748
749
  		datagrams = -EFAULT;
  
  	return datagrams;
  }
361d93c46   Heiko Carstens   net/compat: conve...
750
  COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
  {
  	int ret;
  	u32 a[6];
  	u32 a0, a1;
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
755

228e548e6   Anton Blanchard   net: Add sendmmsg...
756
  	if (call < SYS_SOCKET || call > SYS_SENDMMSG)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
761
  		return -EINVAL;
  	if (copy_from_user(a, args, nas[call]))
  		return -EFAULT;
  	a0 = a[0];
  	a1 = a[1];
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
762

e71a4783a   Stephen Hemminger   [NET] core: white...
763
  	switch (call) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
767
768
769
770
771
772
773
774
775
776
  	case SYS_SOCKET:
  		ret = sys_socket(a0, a1, a[2]);
  		break;
  	case SYS_BIND:
  		ret = sys_bind(a0, compat_ptr(a1), a[2]);
  		break;
  	case SYS_CONNECT:
  		ret = sys_connect(a0, compat_ptr(a1), a[2]);
  		break;
  	case SYS_LISTEN:
  		ret = sys_listen(a0, a1);
  		break;
  	case SYS_ACCEPT:
de11defeb   Ulrich Drepper   reintroduce accept4
777
  		ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
  		break;
  	case SYS_GETSOCKNAME:
  		ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
  		break;
  	case SYS_GETPEERNAME:
  		ret = sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
  		break;
  	case SYS_SOCKETPAIR:
  		ret = sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
  		break;
  	case SYS_SEND:
  		ret = sys_send(a0, compat_ptr(a1), a[2], a[3]);
  		break;
  	case SYS_SENDTO:
  		ret = sys_sendto(a0, compat_ptr(a1), a[2], a[3], compat_ptr(a[4]), a[5]);
  		break;
  	case SYS_RECV:
1dacc76d0   Johannes Berg   net/compat/wext: ...
795
  		ret = compat_sys_recv(a0, compat_ptr(a1), a[2], a[3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
  		break;
  	case SYS_RECVFROM:
1dacc76d0   Johannes Berg   net/compat/wext: ...
798
799
  		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
800
801
  		break;
  	case SYS_SHUTDOWN:
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
802
  		ret = sys_shutdown(a0, a1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
807
808
809
810
811
812
813
814
  		break;
  	case SYS_SETSOCKOPT:
  		ret = compat_sys_setsockopt(a0, a1, a[2],
  				compat_ptr(a[3]), a[4]);
  		break;
  	case SYS_GETSOCKOPT:
  		ret = compat_sys_getsockopt(a0, a1, a[2],
  				compat_ptr(a[3]), compat_ptr(a[4]));
  		break;
  	case SYS_SENDMSG:
  		ret = compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
  		break;
228e548e6   Anton Blanchard   net: Add sendmmsg...
815
816
817
  	case SYS_SENDMMSG:
  		ret = compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
  	case SYS_RECVMSG:
  		ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
  		break;
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
821
822
823
824
  	case SYS_RECVMMSG:
  		ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
  					  compat_ptr(a[4]));
  		break;
de11defeb   Ulrich Drepper   reintroduce accept4
825
826
  	case SYS_ACCEPT4:
  		ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
aaca0bdca   Ulrich Drepper   flag parameters: ...
827
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
830
831
832
833
  	default:
  		ret = -EINVAL;
  		break;
  	}
  	return ret;
  }