summaryrefslogtreecommitdiff
path: root/sys/compat
diff options
context:
space:
mode:
authorrtr <rtr@NetBSD.org>2015-04-03 20:01:07 +0000
committerrtr <rtr@NetBSD.org>2015-04-03 20:01:07 +0000
commit0da58ac00a9b5753aba6c2f4714b9d499759d1f2 (patch)
treef85b2abd805d39ad26a562d1836377ec5f5a012d /sys/compat
parent96d58810e5e839733058d3448402f7aac437b4ea (diff)
* change pr_bind to accept struct sockaddr * instead of struct mbuf *
* update protocol bind implementations to use/expect sockaddr * instead of mbuf * * introduce sockaddr_big struct for storage of addr data passed via sys_bind; sockaddr_big is of sufficient size and alignment to accommodate all addr data sizes received. * modify sys_bind to allocate sockaddr_big instead of using an mbuf. * bump kernel version to 7.99.9 for change to pr_bind() parameter type. Patch posted to tech-net@ http://mail-index.netbsd.org/tech-net/2015/03/15/msg005004.html The choice to use a new structure sockaddr_big has been retained since changing sockaddr_storage size would lead to unnecessary ABI change. The use of the new structure does not preclude future work that increases the size of sockaddr_storage and at that time sockaddr_big may be trivially replaced. Tested by mrg@ and myself, discussed with rmind@, posted to tech-net@
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/linux/common/linux_socket.c83
-rw-r--r--sys/compat/svr4/svr4_stream.c24
2 files changed, 87 insertions, 20 deletions
diff --git a/sys/compat/linux/common/linux_socket.c b/sys/compat/linux/common/linux_socket.c
index dbad73174b6..442c5d1923c 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.122 2014/11/26 09:53:53 ozaki-r Exp $ */
+/* $NetBSD: linux_socket.c,v 1.123 2015/04/03 20:01:07 rtr Exp $ */
/*-
* Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.122 2014/11/26 09:53:53 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.123 2015/04/03 20:01:07 rtr Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@@ -121,6 +121,8 @@ int linux_getifconf(struct lwp *, register_t *, void *);
int linux_getifhwaddr(struct lwp *, register_t *, u_int, void *);
static int linux_get_sa(struct lwp *, int, struct mbuf **,
const struct osockaddr *, unsigned int);
+static int linux_get_sa_sb(struct lwp *, int, struct sockaddr_big *,
+ const struct osockaddr *, socklen_t);
static int linux_sa_put(struct osockaddr *osa);
static int linux_to_bsd_msg_flags(int);
static int bsd_to_linux_msg_flags(int);
@@ -1445,14 +1447,14 @@ linux_sys_bind(struct lwp *l, const struct linux_sys_bind_args *uap, register_t
syscallarg(int) namelen;
} */
int error;
- struct mbuf *nam;
+ struct sockaddr_big sb;
- error = linux_get_sa(l, SCARG(uap, s), &nam, SCARG(uap, name),
+ error = linux_get_sa_sb(l, SCARG(uap, s), &sb, SCARG(uap, name),
SCARG(uap, namelen));
if (error)
return (error);
- return do_sys_bind(l, SCARG(uap, s), nam);
+ return do_sys_bind(l, SCARG(uap, s), (struct sockaddr *)&sb);
}
int
@@ -1493,6 +1495,77 @@ linux_sys_getpeername(struct lwp *l, const struct linux_sys_getpeername_args *ua
return (0);
}
+static int
+linux_get_sa_sb(struct lwp *l, int s, struct sockaddr_big *sb,
+ const struct osockaddr *name, socklen_t namelen)
+{
+ int error, bdom;
+
+ if (namelen > UCHAR_MAX ||
+ namelen <= offsetof(struct sockaddr_big, sb_data))
+ return EINVAL;
+
+ error = copyin(name, sb, namelen);
+ if (error)
+ return error;
+
+ bdom = linux_to_bsd_domain(sb->sb_family);
+ if (bdom == -1)
+ return EINVAL;
+
+ /*
+ * If the family is unspecified, use address family of the socket.
+ * This avoid triggering strict family checks in netinet/in_pcb.c et.al.
+ */
+ if (bdom == AF_UNSPEC) {
+ struct socket *so;
+
+ /* fd_getsock() will use the descriptor for us */
+ if ((error = fd_getsock(s, &so)) != 0)
+ return error;
+
+ bdom = so->so_proto->pr_domain->dom_family;
+ fd_putfile(s);
+ }
+
+ /*
+ * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
+ * which lacks the scope id compared with RFC2553 one. If we detect
+ * the situation, reject the address and write a message to system log.
+ *
+ * Still accept addresses for which the scope id is not used.
+ */
+ if (bdom == AF_INET6 &&
+ namelen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sb;
+ if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) &&
+ (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
+ struct proc *p = l->l_proc;
+ int uid = l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1;
+
+ log(LOG_DEBUG,
+ "pid %d (%s), uid %d: obsolete pre-RFC2553 "
+ "sockaddr_in6 rejected",
+ p->p_pid, p->p_comm, uid);
+ return EINVAL;
+ }
+ namelen = sizeof(struct sockaddr_in6);
+ sin6->sin6_scope_id = 0;
+ }
+
+ if (bdom == AF_INET)
+ namelen = sizeof(struct sockaddr_in);
+
+ sb->sb_family = bdom;
+ sb->sb_len = namelen;
+ ktrkuser("mbsoname", sb, namelen);
+ return 0;
+}
+
/*
* Copy the osockaddr structure pointed to by osa to mbuf, adjust
* family and convert to sockaddr.
diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c
index 4d263cfbbac..df09dd000d1 100644
--- a/sys/compat/svr4/svr4_stream.c
+++ b/sys/compat/svr4/svr4_stream.c
@@ -1,4 +1,4 @@
-/* $NetBSD: svr4_stream.c,v 1.81 2014/09/05 09:21:55 matt Exp $ */
+/* $NetBSD: svr4_stream.c,v 1.82 2015/04/03 20:01:07 rtr Exp $ */
/*-
* Copyright (c) 1994, 2008 The NetBSD Foundation, Inc.
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: svr4_stream.c,v 1.81 2014/09/05 09:21:55 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: svr4_stream.c,v 1.82 2015/04/03 20:01:07 rtr Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -752,10 +752,10 @@ ti_bind(file_t *fp, int fd, struct svr4_strioctl *ioc, struct lwp *l)
struct svr4_strm *st = svr4_stream_get(fp);
struct sockaddr_in sain;
struct sockaddr_un saun;
- void *skp, *sup = NULL;
+ struct sockaddr_big *sbig;
+ void *sup = NULL;
int sasize;
struct svr4_strmcmd bnd;
- struct mbuf *name;
if (st == NULL) {
DPRINTF(("ti_bind: bad file descriptor\n"));
@@ -775,8 +775,8 @@ ti_bind(file_t *fp, int fd, struct svr4_strioctl *ioc, struct lwp *l)
switch (st->s_family) {
case AF_INET:
- skp = &sain;
- sasize = sizeof(sain);
+ sbig = (struct sockaddr_big *)&sain;
+ sbig->sb_len = sasize = sizeof(sain);
if (bnd.offs == 0)
goto reply;
@@ -789,8 +789,8 @@ ti_bind(file_t *fp, int fd, struct svr4_strioctl *ioc, struct lwp *l)
break;
case AF_LOCAL:
- skp = &saun;
- sasize = sizeof(saun);
+ sbig = (struct sockaddr_big *)&saun;
+ sbig->sb_len = sasize = sizeof(saun);
if (bnd.offs == 0)
goto reply;
@@ -814,15 +814,9 @@ ti_bind(file_t *fp, int fd, struct svr4_strioctl *ioc, struct lwp *l)
return ENOSYS;
}
- name = m_get(M_WAIT, MT_SONAME);
- if (sasize > MLEN)
- MEXTMALLOC(name, sasize, M_WAITOK);
-
- memcpy(mtod(name, void *), skp, sasize);
-
DPRINTF(("TI_BIND: fileno %d\n", fd));
- error = do_sys_bind(l, fd, name);
+ error = do_sys_bind(l, fd, (struct sockaddr *)sbig);
if (error != 0) {
DPRINTF(("TI_BIND: bind failed %d\n", error));
return error;