diff --git a/sys/compat/linux/common/linux_socket.c b/sys/compat/linux/common/linux_socket.c index 00a7434ec8c2..36d315b09c69 100644 --- a/sys/compat/linux/common/linux_socket.c +++ b/sys/compat/linux/common/linux_socket.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_socket.c,v 1.52 2004/09/05 09:38:17 jdolecek Exp $ */ +/* $NetBSD: linux_socket.c,v 1.53 2004/09/12 15:32:55 jdolecek Exp $ */ /*- * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. @@ -42,7 +42,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.52 2004/09/05 09:38:17 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.53 2004/09/12 15:32:55 jdolecek Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -60,6 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.52 2004/09/05 09:38:17 jdolecek E #include #include #include +#include #include #include #include @@ -114,8 +115,8 @@ int linux_to_bsd_ip_sockopt __P((int)); int linux_to_bsd_tcp_sockopt __P((int)); int linux_to_bsd_udp_sockopt __P((int)); int linux_getifhwaddr __P((struct proc *, register_t *, u_int, void *)); -static int linux_sa_get __P((struct proc *, caddr_t *sgp, struct sockaddr **sap, - const struct osockaddr *osa, int *osalen)); +static int linux_sa_get __P((struct proc *, int, caddr_t *, struct sockaddr **, + const struct osockaddr *, int *)); static int linux_sa_put __P((struct osockaddr *osa)); static int linux_to_bsd_msg_flags __P((int)); static int bsd_to_linux_msg_flags __P((int)); @@ -386,7 +387,9 @@ linux_sys_sendto(l, v, retval) int error; caddr_t sg = stackgap_init(p, 0); - if ((error = linux_sa_get(p, &sg, &sa, SCARG(uap, to), &tolen))) + error = linux_sa_get(p, SCARG(uap, s), &sg, &sa, + SCARG(uap, to), &tolen); + if (error) return (error); SCARG(&bsa, to) = sa; @@ -440,7 +443,7 @@ linux_sys_sendmsg(l, v, retval) struct sockaddr *sa; sg = stackgap_init(p, 0); - error = linux_sa_get(p, &sg, &sa, + error = linux_sa_get(p, SCARG(uap, s), &sg, &sa, (struct osockaddr *) msg.msg_name, &msg.msg_namelen); if (error) goto done; @@ -1322,7 +1325,8 @@ linux_sys_connect(l, v, retval) int namlen; namlen = SCARG(uap, namelen); - error = linux_sa_get(p, &sg, &sa, SCARG(uap, name), &namlen); + error = linux_sa_get(p, SCARG(uap, s), &sg, &sa, + SCARG(uap, name), &namlen); if (error) return (error); @@ -1381,7 +1385,8 @@ linux_sys_bind(l, v, retval) struct sockaddr *sa; caddr_t sg = stackgap_init(p, 0); - error = linux_sa_get(p, &sg, &sa, SCARG(uap, name), &namlen); + error = linux_sa_get(p, SCARG(uap, s), &sg, &sa, + SCARG(uap, name), &namlen); if (error) return (error); @@ -1443,8 +1448,9 @@ linux_sys_getpeername(l, v, retval) * the converted structure there, address on stackgap returned in sap. */ static int -linux_sa_get(p, sgp, sap, osa, osalen) +linux_sa_get(p, s, sgp, sap, osa, osalen) struct proc *p; + int s; caddr_t *sgp; struct sockaddr **sap; const struct osockaddr *osa; @@ -1520,8 +1526,31 @@ linux_sa_get(p, sgp, sap, osa, osalen) error = EINVAL; goto out; } - } else -#endif + } +#endif + + /* + * If the family is unspecified, use address family of the + * socket. This avoid triggering COMPAT_43 struct socket family check + * in sockargs() on little-endian machines, and strict family checks + * in netinet/in_pcb.c et.al. + */ + if (bdom == AF_UNSPEC) { + struct file *fp; + struct socket *so; + + /* getsock() will use the descriptor for us */ + if ((error = getsock(p->p_fd, s, &fp)) != 0) + goto out; + + so = (struct socket *)fp->f_data; + bdom = so->so_proto->pr_domain->dom_family; + + FILE_UNUSE(fp, p); + + DPRINTF(("AF_UNSPEC family adjusted to %d\n", bdom)); + } + if (bdom == AF_INET) { alloclen = sizeof(struct sockaddr_in); }