1 /*
2  * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
3  *
4  * Copyright (C) 2000		VA Linux Co
5  * Copyright (C) 2000		Don Dugger <n0ano@valinux.com>
6  * Copyright (C) 1999 		Arun Sharma <arun.sharma@intel.com>
7  * Copyright (C) 1997,1998 	Jakub Jelinek (jj@sunsite.mff.cuni.cz)
8  * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
9  * Copyright (C) 2000		Hewlett-Packard Co.
10  * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
11  * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/fs.h>
16 #include <linux/sched.h>
17 #include <linux/types.h>
18 #include <linux/file.h>
19 #include <linux/icmpv6.h>
20 #include <linux/socket.h>
21 #include <linux/filter.h>
22 
23 #include <net/scm.h>
24 #include <net/sock.h>
25 #include <asm/ia32.h>
26 #include <asm/uaccess.h>
27 #include <asm/socket32.h>
28 
29 #define A(__x)		((unsigned long)(__x))
30 #define AA(__x)		((unsigned long)(__x))
31 
32 
iov_from_user32_to_kern(struct iovec * kiov,struct iovec32 * uiov32,int niov)33 static inline int iov_from_user32_to_kern(struct iovec *kiov,
34 					  struct iovec32 *uiov32,
35 					  int niov)
36 {
37 	int tot_len = 0;
38 
39 	while(niov > 0) {
40 		u32 len, buf;
41 
42 		if(get_user(len, &uiov32->iov_len) ||
43 		   get_user(buf, &uiov32->iov_base)) {
44 			tot_len = -EFAULT;
45 			break;
46 		}
47 		tot_len += len;
48 		kiov->iov_base = (void *)A(buf);
49 		kiov->iov_len = (__kernel_size_t) len;
50 		uiov32++;
51 		kiov++;
52 		niov--;
53 	}
54 	return tot_len;
55 }
56 
msghdr_from_user32_to_kern(struct msghdr * kmsg,struct msghdr32 * umsg)57 static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
58 					     struct msghdr32 *umsg)
59 {
60 	u32 tmp1, tmp2, tmp3;
61 	int err;
62 
63 	err = get_user(tmp1, &umsg->msg_name);
64 	err |= __get_user(tmp2, &umsg->msg_iov);
65 	err |= __get_user(tmp3, &umsg->msg_control);
66 	if (err)
67 		return -EFAULT;
68 
69 	kmsg->msg_name = (void *)A(tmp1);
70 	kmsg->msg_iov = (struct iovec *)A(tmp2);
71 	kmsg->msg_control = (void *)A(tmp3);
72 
73 	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
74 	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
75 	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
76 	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
77 
78 	return err;
79 }
80 
81 /* I've named the args so it is easy to tell whose space the pointers are in. */
verify_iovec32(struct msghdr * kern_msg,struct iovec * kern_iov,char * kern_address,int mode)82 static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
83 			  char *kern_address, int mode)
84 {
85 	int tot_len;
86 
87 	if(kern_msg->msg_namelen) {
88 		if(mode==VERIFY_READ) {
89 			int err = move_addr_to_kernel(kern_msg->msg_name,
90 						      kern_msg->msg_namelen,
91 						      kern_address);
92 			if(err < 0)
93 				return err;
94 		}
95 		kern_msg->msg_name = kern_address;
96 	} else
97 		kern_msg->msg_name = NULL;
98 
99 	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
100 		if (kern_msg->msg_iovlen > (2*PAGE_SIZE)/ sizeof(struct iovec))
101 			return -EINVAL;
102 		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
103 				   GFP_KERNEL);
104 		if(!kern_iov)
105 			return -ENOMEM;
106 	}
107 
108 	tot_len = iov_from_user32_to_kern(kern_iov,
109 					  (struct iovec32 *)kern_msg->msg_iov,
110 					  kern_msg->msg_iovlen);
111 	if(tot_len >= 0)
112 		kern_msg->msg_iov = kern_iov;
113 	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
114 		kfree(kern_iov);
115 
116 	return tot_len;
117 }
118 
119 /* There is a lot of hair here because the alignment rules (and
120  * thus placement) of cmsg headers and length are different for
121  * 32-bit apps.  -DaveM
122  */
cmsghdr_from_user32_to_kern(struct msghdr * kmsg,unsigned char * stackbuf,int stackbuf_size)123 static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
124 				       unsigned char *stackbuf, int stackbuf_size)
125 {
126 	struct cmsghdr32 *ucmsg;
127 	struct cmsghdr *kcmsg, *kcmsg_base;
128 	__kernel_size_t32 ucmlen;
129 	__kernel_size_t kcmlen, tmp;
130 	int err = -EFAULT;
131 
132 	kcmlen = 0;
133 	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
134 	ucmsg = CMSG32_FIRSTHDR(kmsg);
135 	while(ucmsg != NULL) {
136 		if (get_user(ucmlen, &ucmsg->cmsg_len))
137 			return -EFAULT;
138 
139 		/* Catch bogons. */
140 		if (!CMSG32_OK(ucmlen, ucmsg, kmsg))
141 			return -EINVAL;
142 
143 		if (kmsg->msg_controllen > 65536)
144 			return -EINVAL;
145 
146 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
147 		       CMSG_ALIGN(sizeof(struct cmsghdr)));
148 		kcmlen += tmp;
149 		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
150 	}
151 	if(kcmlen == 0)
152 		return -EINVAL;
153 
154 	/* The kcmlen holds the 64-bit version of the control length.
155 	 * It may not be modified as we do not stick it into the kmsg
156 	 * until we have successfully copied over all of the data
157 	 * from the user.
158 	 */
159 	if(kcmlen > stackbuf_size)
160 		kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
161 	if(kcmsg == NULL)
162 		return -ENOBUFS;
163 
164 	/* Now copy them over neatly. */
165 	memset(kcmsg, 0, kcmlen);
166 	ucmsg = CMSG32_FIRSTHDR(kmsg);
167 	while(ucmsg != NULL) {
168 		if (__get_user(ucmlen, &ucmsg->cmsg_len))
169 			goto Efault;
170 		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
171 		       CMSG_ALIGN(sizeof(struct cmsghdr)));
172 		if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
173 			goto Einval;
174 		kcmsg->cmsg_len = tmp;
175 		if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
176 		    __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
177 		    copy_from_user(CMSG_DATA(kcmsg),
178 				   CMSG32_DATA(ucmsg),
179 				   (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
180 			goto Efault;
181 
182 		/* Advance. */
183 		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
184 		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
185 	}
186 
187 	/* Ok, looks like we made it.  Hook it up and return success. */
188 	kmsg->msg_control = kcmsg_base;
189 	kmsg->msg_controllen = kcmlen;
190 	return 0;
191 
192 Einval:
193 	err = -EINVAL;
194 Efault:
195 	if (kcmsg_base != (struct cmsghdr *)stackbuf)
196 		kfree(kcmsg_base);
197 	return err;
198 }
199 
put_cmsg32(struct msghdr * kmsg,int level,int type,int len,void * data)200 static void put_cmsg32(struct msghdr *kmsg, int level, int type,
201 		       int len, void *data)
202 {
203 	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
204 	struct cmsghdr32 cmhdr;
205 	int cmlen = CMSG32_LEN(len);
206 
207 	if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
208 		kmsg->msg_flags |= MSG_CTRUNC;
209 		return;
210 	}
211 
212 	if(kmsg->msg_controllen < cmlen) {
213 		kmsg->msg_flags |= MSG_CTRUNC;
214 		cmlen = kmsg->msg_controllen;
215 	}
216 	cmhdr.cmsg_level = level;
217 	cmhdr.cmsg_type = type;
218 	cmhdr.cmsg_len = cmlen;
219 
220 	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
221 		return;
222 	if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))
223 		return;
224 	cmlen = CMSG32_SPACE(len);
225 	kmsg->msg_control += cmlen;
226 	kmsg->msg_controllen -= cmlen;
227 }
228 
scm_detach_fds32(struct msghdr * kmsg,struct scm_cookie * scm)229 static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
230 {
231 	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
232 	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);
233 	int fdnum = scm->fp->count;
234 	struct file **fp = scm->fp->fp;
235 	int *cmfptr;
236 	int err = 0, i;
237 
238 	if (fdnum < fdmax)
239 		fdmax = fdnum;
240 
241 	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {
242 		int new_fd;
243 		err = get_unused_fd();
244 		if (err < 0)
245 			break;
246 		new_fd = err;
247 		err = put_user(new_fd, cmfptr);
248 		if (err) {
249 			put_unused_fd(new_fd);
250 			break;
251 		}
252 		/* Bump the usage count and install the file. */
253 		get_file(fp[i]);
254 		fd_install(new_fd, fp[i]);
255 	}
256 
257 	if (i > 0) {
258 		int cmlen = CMSG32_LEN(i * sizeof(int));
259 		if (!err)
260 			err = put_user(SOL_SOCKET, &cm->cmsg_level);
261 		if (!err)
262 			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
263 		if (!err)
264 			err = put_user(cmlen, &cm->cmsg_len);
265 		if (!err) {
266 			cmlen = CMSG32_SPACE(i * sizeof(int));
267 			kmsg->msg_control += cmlen;
268 			kmsg->msg_controllen -= cmlen;
269 		}
270 	}
271 	if (i < fdnum)
272 		kmsg->msg_flags |= MSG_CTRUNC;
273 
274 	/*
275 	 * All of the files that fit in the message have had their
276 	 * usage counts incremented, so we just free the list.
277 	 */
278 	__scm_destroy(scm);
279 }
280 
281 /* In these cases we (currently) can just copy to data over verbatim
282  * because all CMSGs created by the kernel have well defined types which
283  * have the same layout in both the 32-bit and 64-bit API.  One must add
284  * some special cased conversions here if we start sending control messages
285  * with incompatible types.
286  *
287  * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
288  * we do our work.  The remaining cases are:
289  *
290  * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean
291  *		IP_TTL		int			32-bit clean
292  *		IP_TOS		__u8			32-bit clean
293  *		IP_RECVOPTS	variable length		32-bit clean
294  *		IP_RETOPTS	variable length		32-bit clean
295  *		(these last two are clean because the types are defined
296  *		 by the IPv4 protocol)
297  *		IP_RECVERR	struct sock_extended_err +
298  *				struct sockaddr_in	32-bit clean
299  * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err +
300  *				struct sockaddr_in6	32-bit clean
301  *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean
302  *		IPV6_HOPLIMIT	int			32-bit clean
303  *		IPV6_FLOWINFO	u32			32-bit clean
304  *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean
305  *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean
306  *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean
307  *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean
308  */
cmsg32_recvmsg_fixup(struct msghdr * kmsg,unsigned long orig_cmsg_uptr,__kernel_size_t orig_cmsg_len)309 static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
310 		unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
311 {
312 	unsigned char *workbuf, *wp;
313 	unsigned long bufsz, space_avail;
314 	struct cmsghdr *ucmsg;
315 
316 	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
317 	space_avail = kmsg->msg_controllen + bufsz;
318 	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
319 	if(workbuf == NULL)
320 		goto fail;
321 
322 	/* To make this more sane we assume the kernel sends back properly
323 	 * formatted control messages.  Because of how the kernel will truncate
324 	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
325 	 */
326 	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
327 	while(((unsigned long)ucmsg) <=
328 	      (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
329 		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
330 		int clen64, clen32;
331 
332 		/* UCMSG is the 64-bit format CMSG entry in user-space.
333 		 * KCMSG32 is within the kernel space temporary buffer
334 		 * we use to convert into a 32-bit style CMSG.
335 		 */
336 		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
337 		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
338 		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
339 
340 		clen64 = kcmsg32->cmsg_len;
341 		if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
342 				(clen64 > (orig_cmsg_len + wp - workbuf)))
343 			break;
344 		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
345 			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
346 		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
347 			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
348 		kcmsg32->cmsg_len = clen32;
349 
350 		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
351 		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
352 	}
353 
354 	/* Copy back fixed up data, and adjust pointers. */
355 	bufsz = (wp - workbuf);
356 	copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
357 
358 	kmsg->msg_control = (struct cmsghdr *)
359 		(((char *)orig_cmsg_uptr) + bufsz);
360 	kmsg->msg_controllen = space_avail - bufsz;
361 
362 	kfree(workbuf);
363 	return;
364 
365 fail:
366 	/* If we leave the 64-bit format CMSG chunks in there,
367 	 * the application could get confused and crash.  So to
368 	 * ensure greater recovery, we report no CMSGs.
369 	 */
370 	kmsg->msg_controllen += bufsz;
371 	kmsg->msg_control = (void *) orig_cmsg_uptr;
372 }
373 
sys32_sendmsg(int fd,struct msghdr32 * user_msg,unsigned user_flags)374 asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
375 {
376 	struct socket *sock;
377 	char address[MAX_SOCK_ADDR];
378 	struct iovec iov[UIO_FASTIOV];
379 	unsigned char ctl[sizeof(struct cmsghdr) + 20];
380 	unsigned char *ctl_buf = ctl;
381 	struct msghdr kern_msg;
382 	int err, total_len;
383 
384 	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
385 		return -EFAULT;
386 	if(kern_msg.msg_iovlen > UIO_MAXIOV)
387 		return -EINVAL;
388 	err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
389 	if (err < 0)
390 		goto out;
391 	total_len = err;
392 
393 	if(kern_msg.msg_controllen) {
394 		err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
395 		if(err)
396 			goto out_freeiov;
397 		ctl_buf = kern_msg.msg_control;
398 	}
399 	kern_msg.msg_flags = user_flags;
400 
401 	sock = sockfd_lookup(fd, &err);
402 	if (sock != NULL) {
403 		if (sock->file->f_flags & O_NONBLOCK)
404 			kern_msg.msg_flags |= MSG_DONTWAIT;
405 		err = sock_sendmsg(sock, &kern_msg, total_len);
406 		sockfd_put(sock);
407 	}
408 
409 	/* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
410 	if(ctl_buf != ctl)
411 		kfree(ctl_buf);
412 out_freeiov:
413 	if(kern_msg.msg_iov != iov)
414 		kfree(kern_msg.msg_iov);
415 out:
416 	return err;
417 }
418 
sys32_recvmsg(int fd,struct msghdr32 * user_msg,unsigned int user_flags)419 asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
420 {
421 	struct iovec iovstack[UIO_FASTIOV];
422 	struct msghdr kern_msg;
423 	char addr[MAX_SOCK_ADDR];
424 	struct socket *sock;
425 	struct iovec *iov = iovstack;
426 	struct sockaddr *uaddr;
427 	int *uaddr_len;
428 	unsigned long cmsg_ptr;
429 	__kernel_size_t cmsg_len;
430 	int err, total_len, len = 0;
431 
432 	if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
433 		return -EFAULT;
434 	if(kern_msg.msg_iovlen > UIO_MAXIOV)
435 		return -EINVAL;
436 
437 	uaddr = kern_msg.msg_name;
438 	uaddr_len = &user_msg->msg_namelen;
439 	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
440 	if (err < 0)
441 		goto out;
442 	total_len = err;
443 
444 	cmsg_ptr = (unsigned long) kern_msg.msg_control;
445 	cmsg_len = kern_msg.msg_controllen;
446 	kern_msg.msg_flags = 0;
447 
448 	sock = sockfd_lookup(fd, &err);
449 	if (sock != NULL) {
450 		struct scm_cookie scm;
451 
452 		if (sock->file->f_flags & O_NONBLOCK)
453 			user_flags |= MSG_DONTWAIT;
454 		memset(&scm, 0, sizeof(scm));
455 		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
456 					 user_flags, &scm);
457 		if(err >= 0) {
458 			len = err;
459 			if(!kern_msg.msg_control) {
460 				if(sock->passcred || scm.fp)
461 					kern_msg.msg_flags |= MSG_CTRUNC;
462 				if(scm.fp)
463 					__scm_destroy(&scm);
464 			} else {
465 				/* If recvmsg processing itself placed some
466 				 * control messages into user space, it's is
467 				 * using 64-bit CMSG processing, so we need
468 				 * to fix it up before we tack on more stuff.
469 				 */
470 				if((unsigned long) kern_msg.msg_control != cmsg_ptr)
471 					cmsg32_recvmsg_fixup(&kern_msg,
472 							cmsg_ptr, cmsg_len);
473 
474 				/* Wheee... */
475 				if(sock->passcred)
476 					put_cmsg32(&kern_msg,
477 						   SOL_SOCKET, SCM_CREDENTIALS,
478 						   sizeof(scm.creds), &scm.creds);
479 				if(scm.fp != NULL)
480 					scm_detach_fds32(&kern_msg, &scm);
481 			}
482 		}
483 		sockfd_put(sock);
484 	}
485 
486 	if(uaddr != NULL && err >= 0)
487 		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
488 	if(cmsg_ptr != 0 && err >= 0) {
489 		unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
490 		__kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
491 		err |= __put_user(uclen, &user_msg->msg_controllen);
492 	}
493 	if(err >= 0)
494 		err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
495 	if(kern_msg.msg_iov != iov)
496 		kfree(kern_msg.msg_iov);
497 out:
498 	if(err < 0)
499 		return err;
500 	return len;
501 }
502 
503 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
504 				     char *optval, int optlen);
505 
do_set_attach_filter(int fd,int level,int optname,char * optval,int optlen)506 static int do_set_attach_filter(int fd, int level, int optname,
507 				char *optval, int optlen)
508 {
509 	struct sock_fprog32 {
510 		__u16 len;
511 		__u32 filter;
512 	} *fprog32 = (struct sock_fprog32 *)optval;
513 	struct sock_fprog kfprog;
514 	mm_segment_t old_fs;
515 	__u32 uptr;
516 	int ret;
517 
518 	if (get_user(kfprog.len, &fprog32->len) ||
519 	    __get_user(uptr, &fprog32->filter))
520 		return -EFAULT;
521 
522 	kfprog.filter = (struct sock_filter *)A(uptr);
523 
524 	if (verify_area(VERIFY_WRITE, kfprog.filter, kfprog.len*sizeof(struct sock_filter)))
525 		return -EFAULT;
526 
527 	old_fs = get_fs();
528 	set_fs(KERNEL_DS);
529 	ret = sys_setsockopt(fd, level, optname,
530 			     (char *)&kfprog, sizeof(kfprog));
531 	set_fs(old_fs);
532 
533 	return ret;
534 }
535 
do_set_icmpv6_filter(int fd,int level,int optname,char * optval,int optlen)536 static int do_set_icmpv6_filter(int fd, int level, int optname,
537 				char *optval, int optlen)
538 {
539 	struct icmp6_filter kfilter;
540 	mm_segment_t old_fs;
541 	int ret, i;
542 
543 	if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
544 		return -EFAULT;
545 
546 
547 	for (i = 0; i < 8; i += 2) {
548 		u32 tmp = kfilter.data[i];
549 
550 		kfilter.data[i] = kfilter.data[i + 1];
551 		kfilter.data[i + 1] = tmp;
552 	}
553 
554 	old_fs = get_fs();
555 	set_fs(KERNEL_DS);
556 	ret = sys_setsockopt(fd, level, optname,
557 			     (char *) &kfilter, sizeof(kfilter));
558 	set_fs(old_fs);
559 
560 	return ret;
561 }
562 
sys32_setsockopt(int fd,int level,int optname,char * optval,int optlen)563 asmlinkage long sys32_setsockopt(int fd, int level, int optname,
564 				char *optval, int optlen)
565 {
566 	if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER)
567 		return do_set_attach_filter(fd, level, optname,
568 					    optval, optlen);
569 	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
570 		return do_set_icmpv6_filter(fd, level, optname,
571 					    optval, optlen);
572 
573 	return sys_setsockopt(fd, level, optname, optval, optlen);
574 }
575 
576 
577 /* Argument list sizes for sys_socketcall */
578 #define AL(x) ((x) * sizeof(u32))
579 static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
580                                 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
581                                 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
582 #undef AL
583 
584 extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
585 extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr,
586 				  int addrlen);
587 extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr,
588 				 int *upeer_addrlen);
589 extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr,
590 				      int *usockaddr_len);
591 extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr,
592 				      int *usockaddr_len);
593 extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags);
594 extern asmlinkage long sys_sendto(int fd, u32 buff, __kernel_size_t32 len,
595 				   unsigned flags, u32 addr, int addr_len);
596 extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags);
597 extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
598 				     unsigned flags, u32 addr, u32 addr_len);
599 extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
600 				       u32 optval, u32 optlen);
601 
602 extern asmlinkage long sys_socket(int family, int type, int protocol);
603 extern asmlinkage long sys_socketpair(int family, int type, int protocol,
604 				     int usockvec[2]);
605 extern asmlinkage long sys_shutdown(int fd, int how);
606 extern asmlinkage long sys_listen(int fd, int backlog);
607 
sys32_socketcall(int call,u32 * args)608 asmlinkage long sys32_socketcall(int call, u32 *args)
609 {
610 	int ret;
611 	u32 a[6];
612 	u32 a0,a1;
613 
614 	if (call<SYS_SOCKET||call>SYS_RECVMSG)
615 		return -EINVAL;
616 	if (copy_from_user(a, args, nas[call]))
617 		return -EFAULT;
618 	a0=a[0];
619 	a1=a[1];
620 
621 	switch(call)
622 	{
623 		case SYS_SOCKET:
624 			ret = sys_socket(a0, a1, a[2]);
625 			break;
626 		case SYS_BIND:
627 			ret = sys_bind(a0, (struct sockaddr *)A(a1), a[2]);
628 			break;
629 		case SYS_CONNECT:
630 			ret = sys_connect(a0, (struct sockaddr *)A(a1), a[2]);
631 			break;
632 		case SYS_LISTEN:
633 			ret = sys_listen(a0, a1);
634 			break;
635 		case SYS_ACCEPT:
636 			ret = sys_accept(a0, (struct sockaddr *)A(a1),
637 					  (int *)A(a[2]));
638 			break;
639 		case SYS_GETSOCKNAME:
640 			ret = sys_getsockname(a0, (struct sockaddr *)A(a1),
641 					       (int *)A(a[2]));
642 			break;
643 		case SYS_GETPEERNAME:
644 			ret = sys_getpeername(a0, (struct sockaddr *)A(a1),
645 					       (int *)A(a[2]));
646 			break;
647 		case SYS_SOCKETPAIR:
648 			ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
649 			break;
650 		case SYS_SEND:
651 			ret = sys_send(a0, (void *)A(a1), a[2], a[3]);
652 			break;
653 		case SYS_SENDTO:
654 			ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]);
655 			break;
656 		case SYS_RECV:
657 			ret = sys_recv(a0, (void *)A(a1), a[2], a[3]);
658 			break;
659 		case SYS_RECVFROM:
660 			ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
661 			break;
662 		case SYS_SHUTDOWN:
663 			ret = sys_shutdown(a0,a1);
664 			break;
665 		case SYS_SETSOCKOPT:
666 			ret = sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]),
667 					      a[4]);
668 			break;
669 		case SYS_GETSOCKOPT:
670 			ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]);
671 			break;
672 		case SYS_SENDMSG:
673 			ret = sys32_sendmsg(a0, (struct msghdr32 *)A(a1),
674 					     a[2]);
675 			break;
676 		case SYS_RECVMSG:
677 			ret = sys32_recvmsg(a0, (struct msghdr32 *)A(a1),
678 					     a[2]);
679 			break;
680 		default:
681 			ret = -EINVAL;
682 			break;
683 	}
684 	return ret;
685 }
686