From owner-dev-commits-src-branches@freebsd.org Mon May 17 17:49:03 2021 Return-Path: Delivered-To: dev-commits-src-branches@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id C429064EC0A; Mon, 17 May 2021 17:49:03 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4FkRTC5C2Hz4l62; Mon, 17 May 2021 17:49:03 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 9A8931098A; Mon, 17 May 2021 17:49:03 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 14HHn3tl076433; Mon, 17 May 2021 17:49:03 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 14HHn3mU076432; Mon, 17 May 2021 17:49:03 GMT (envelope-from git) Date: Mon, 17 May 2021 17:49:03 GMT Message-Id: <202105171749.14HHn3mU076432@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: 1e066db6cdad - stable/13 - Add missing sockaddr length and family validation to various protocols MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 1e066db6cdad4f3d4934bad487db68d3a7872727 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-branches@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commits to the stable branches of the FreeBSD src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 May 2021 17:49:03 -0000 The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=1e066db6cdad4f3d4934bad487db68d3a7872727 commit 1e066db6cdad4f3d4934bad487db68d3a7872727 Author: Mark Johnston AuthorDate: 2021-05-03 16:51:04 +0000 Commit: Mark Johnston CommitDate: 2021-05-17 17:43:07 +0000 Add missing sockaddr length and family validation to various protocols Several protocol methods take a sockaddr as input. In some cases the sockaddr lengths were not being validated, or were validated after some out-of-bounds accesses could occur. Add requisite checking to various protocol entry points, and convert some existing checks to assertions where appropriate. Reported by: syzkaller+KASAN Reviewed by: tuexen, melifaro Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D29519 (cherry picked from commit f161d294b92732df6254a89f393ab24999e122bf) --- sys/dev/hyperv/hvsock/hv_sock.c | 9 ++++++++ sys/netgraph/ng_socket.c | 19 ++++++++++++---- sys/netinet/in_pcb.c | 28 +++++++++++------------ sys/netinet/ip_divert.c | 21 ++++++++++++++--- sys/netinet/raw_ip.c | 14 ++++++++++-- sys/netinet/sctp_usrreq.c | 24 +++++++++----------- sys/netinet/tcp_usrreq.c | 31 ++++++++++++++++---------- sys/netinet/udp_usrreq.c | 28 ++++++++++++++++++++++- sys/netinet6/in6_pcb.c | 25 +++++++++------------ sys/netinet6/raw_ip6.c | 6 +++++ sys/netinet6/sctp6_usrreq.c | 21 +++++++++++++++++ sys/netinet6/send.c | 8 +++++++ sys/netinet6/udp6_usrreq.c | 12 +++++++++- sys/netipsec/keysock.c | 2 +- sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c | 23 +++++++++++++++---- 15 files changed, 202 insertions(+), 69 deletions(-) diff --git a/sys/dev/hyperv/hvsock/hv_sock.c b/sys/dev/hyperv/hvsock/hv_sock.c index d212c2d8c2de..bcc237271465 100644 --- a/sys/dev/hyperv/hvsock/hv_sock.c +++ b/sys/dev/hyperv/hvsock/hv_sock.c @@ -300,6 +300,7 @@ hvs_addr_set(struct sockaddr_hvs *addr, unsigned int port) { memset(addr, 0, sizeof(*addr)); addr->sa_family = AF_HYPERV; + addr->sa_len = sizeof(*addr); addr->hvs_port = port; } @@ -430,6 +431,12 @@ hvs_trans_bind(struct socket *so, struct sockaddr *addr, struct thread *td) __func__, sa->sa_family); return (EAFNOSUPPORT); } + if (sa->sa_len != sizeof(*sa)) { + HVSOCK_DBG(HVSOCK_DBG_ERR, + "%s: Not supported, sa_len is %u\n", + __func__, sa->sa_len); + return (EINVAL); + } HVSOCK_DBG(HVSOCK_DBG_VERBOSE, "%s: binding port = 0x%x\n", __func__, sa->hvs_port); @@ -521,6 +528,8 @@ hvs_trans_connect(struct socket *so, struct sockaddr *nam, struct thread *td) return (EINVAL); if (raddr->sa_family != AF_HYPERV) return (EAFNOSUPPORT); + if (raddr->sa_len != sizeof(*raddr)) + return (EINVAL); mtx_lock(&hvs_trans_socks_mtx); if (so->so_state & diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c index 865e9dd7948f..1c67099a4dc4 100644 --- a/sys/netgraph/ng_socket.c +++ b/sys/netgraph/ng_socket.c @@ -240,11 +240,16 @@ ngc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, goto release; } + if (sap->sg_len > NG_NODESIZ + offsetof(struct sockaddr_ng, sg_data)) { + error = EINVAL; + goto release; + } + /* * Allocate an expendable buffer for the path, chop off * the sockaddr header, and make sure it's NUL terminated. */ - len = sap->sg_len - 2; + len = sap->sg_len - offsetof(struct sockaddr_ng, sg_data); path = malloc(len + 1, M_NETGRAPH_PATH, M_WAITOK); bcopy(sap->sg_data, path, len); path[len] = '\0'; @@ -422,10 +427,16 @@ ngd_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, goto release; } - if (sap == NULL) + if (sap == NULL) { len = 0; /* Make compiler happy. */ - else - len = sap->sg_len - 2; + } else { + if (sap->sg_len > NG_NODESIZ + + offsetof(struct sockaddr_ng, sg_data)) { + error = EINVAL; + goto release; + } + len = sap->sg_len - offsetof(struct sockaddr_ng, sg_data); + } /* * If the user used any of these ways to not specify an address diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 59695ee3715d..857119e8213b 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -647,6 +647,10 @@ in_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ucred *cred) { int anonport, error; + KASSERT(nam == NULL || nam->sa_family == AF_INET, + ("%s: invalid address family for %p", __func__, nam)); + KASSERT(nam == NULL || nam->sa_len == sizeof(struct sockaddr_in), + ("%s: invalid address length for %p", __func__, nam)); INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); @@ -933,16 +937,11 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, return (error); } else { sin = (struct sockaddr_in *)nam; - if (nam->sa_len != sizeof (*sin)) - return (EINVAL); -#ifdef notdef - /* - * We should check the family, but old programs - * incorrectly fail to initialize it. - */ - if (sin->sin_family != AF_INET) - return (EAFNOSUPPORT); -#endif + KASSERT(sin->sin_family == AF_INET, + ("%s: invalid family for address %p", __func__, sin)); + KASSERT(sin->sin_len == sizeof(*sin), + ("%s: invalid length for address %p", __func__, sin)); + error = prison_local_ip4(cred, &sin->sin_addr); if (error) return (error); @@ -1365,6 +1364,11 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, u_short lport, fport; int error; + KASSERT(sin->sin_family == AF_INET, + ("%s: invalid address family for %p", __func__, sin)); + KASSERT(sin->sin_len == sizeof(*sin), + ("%s: invalid address length for %p", __func__, sin)); + /* * Because a global state change doesn't actually occur here, a read * lock is sufficient. @@ -1375,10 +1379,6 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, if (oinpp != NULL) *oinpp = NULL; - if (nam->sa_len != sizeof (*sin)) - return (EINVAL); - if (sin->sin_family != AF_INET) - return (EAFNOSUPPORT); if (sin->sin_port == 0) return (EADDRNOTAVAIL); laddr.s_addr = *laddrp; diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 31b28656ece7..f83a42cb36c9 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -327,6 +327,22 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, struct ipfw_rule_ref *dt; int error, family; + if (control) { + m_freem(control); /* XXX */ + control = NULL; + } + + if (sin != NULL) { + if (sin->sin_family != AF_INET) { + m_freem(m); + return (EAFNOSUPPORT); + } + if (sin->sin_len != sizeof(*sin)) { + m_freem(m); + return (EINVAL); + } + } + /* * An mbuf may hasn't come from userland, but we pretend * that it has. @@ -335,9 +351,6 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, m->m_nextpkt = NULL; M_SETFIB(m, so->so_fibnum); - if (control) - m_freem(control); /* XXX */ - mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL); if (mtag == NULL) { /* this should be normal */ @@ -629,6 +642,8 @@ div_bind(struct socket *so, struct sockaddr *nam, struct thread *td) */ if (nam->sa_family != AF_INET) return EAFNOSUPPORT; + if (nam->sa_len != sizeof(struct sockaddr_in)) + return EINVAL; ((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY; INP_INFO_WLOCK(&V_divcbinfo); INP_WLOCK(inp); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index c9def015343c..89ab6a6bbdad 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -996,6 +996,8 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) struct inpcb *inp; int error; + if (nam->sa_family != AF_INET) + return (EAFNOSUPPORT); if (nam->sa_len != sizeof(*addr)) return (EINVAL); @@ -1070,6 +1072,7 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, { struct inpcb *inp; u_long dst; + int error; inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip_send: inp == NULL")); @@ -1084,9 +1087,16 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, } dst = inp->inp_faddr.s_addr; /* Unlocked read. */ } else { - if (nam == NULL) { + error = 0; + if (nam == NULL) + error = ENOTCONN; + else if (nam->sa_family != AF_INET) + error = EAFNOSUPPORT; + else if (nam->sa_len != sizeof(struct sockaddr_in)) + error = EINVAL; + if (error != 0) { m_freem(m); - return (ENOTCONN); + return (error); } dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; } diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 049368c91b56..fb3e398c2878 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -598,29 +598,27 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { goto connected_type; - } else if (addr == NULL) { + } + + error = 0; + if (addr == NULL) { SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); error = EDESTADDRREQ; - sctp_m_freem(m); - if (control) { - sctp_m_freem(control); - control = NULL; - } - return (error); + } else if (addr->sa_family != AF_INET) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); + error = EAFNOSUPPORT; + } else if (addr->sa_len != sizeof(struct sockaddr_in)) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; } -#ifdef INET6 - if (addr->sa_family != AF_INET) { - /* must be a v4 address! */ - SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); + if (error != 0) { sctp_m_freem(m); if (control) { sctp_m_freem(control); control = NULL; } - error = EDESTADDRREQ; return (error); } -#endif /* INET6 */ connected_type: /* now what about control */ if (control) { diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 31b580bfafcc..8c2a4c85d4d2 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -321,14 +321,16 @@ tcp_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td) struct sockaddr_in *sinp; sinp = (struct sockaddr_in *)nam; - if (nam->sa_len != sizeof (*sinp)) + if (nam->sa_family != AF_INET) + return (EAFNOSUPPORT); + if (nam->sa_len != sizeof(*sinp)) return (EINVAL); + /* * Must check for multicast addresses and disallow binding * to them. */ - if (sinp->sin_family == AF_INET && - IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) + if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) return (EAFNOSUPPORT); TCPDEBUG0; @@ -364,14 +366,16 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *td) u_char vflagsav; sin6 = (struct sockaddr_in6 *)nam; - if (nam->sa_len != sizeof (*sin6)) + if (nam->sa_family != AF_INET6) + return (EAFNOSUPPORT); + if (nam->sa_len != sizeof(*sin6)) return (EINVAL); + /* * Must check for multicast addresses and disallow binding * to them. */ - if (sin6->sin6_family == AF_INET6 && - IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) return (EAFNOSUPPORT); TCPDEBUG0; @@ -542,16 +546,17 @@ tcp_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) struct sockaddr_in *sinp; sinp = (struct sockaddr_in *)nam; + if (nam->sa_family != AF_INET) + return (EAFNOSUPPORT); if (nam->sa_len != sizeof (*sinp)) return (EINVAL); + /* * Must disallow TCP ``connections'' to multicast addresses. */ - if (sinp->sin_family == AF_INET - && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) + if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) return (EAFNOSUPPORT); - if ((sinp->sin_family == AF_INET) && - (ntohl(sinp->sin_addr.s_addr) == INADDR_BROADCAST)) + if (ntohl(sinp->sin_addr.s_addr) == INADDR_BROADCAST) return (EACCES); if ((error = prison_remote_ip4(td->td_ucred, &sinp->sin_addr)) != 0) return (error); @@ -606,13 +611,15 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *td) TCPDEBUG0; sin6 = (struct sockaddr_in6 *)nam; + if (nam->sa_family != AF_INET6) + return (EAFNOSUPPORT); if (nam->sa_len != sizeof (*sin6)) return (EINVAL); + /* * Must disallow TCP ``connections'' to multicast addresses. */ - if (sin6->sin6_family == AF_INET6 - && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) return (EAFNOSUPPORT); inp = sotoinpcb(so); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index c2ad9381850e..16ae0a89bb15 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1626,6 +1626,12 @@ udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); inp = sotoinpcb(so); KASSERT(inp != NULL, ("udp_bind: inp == NULL")); + + if (nam->sa_family != AF_INET) + return (EAFNOSUPPORT); + if (nam->sa_len != sizeof(struct sockaddr_in)) + return (EINVAL); + INP_WLOCK(inp); INP_HASH_WLOCK(pcbinfo); error = in_pcbbind(inp, nam, td->td_ucred); @@ -1666,12 +1672,18 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); inp = sotoinpcb(so); KASSERT(inp != NULL, ("udp_connect: inp == NULL")); + + sin = (struct sockaddr_in *)nam; + if (sin->sin_family != AF_INET) + return (EAFNOSUPPORT); + if (sin->sin_len != sizeof(*sin)) + return (EINVAL); + INP_WLOCK(inp); if (inp->inp_faddr.s_addr != INADDR_ANY) { INP_WUNLOCK(inp); return (EISCONN); } - sin = (struct sockaddr_in *)nam; error = prison_remote_ip4(td->td_ucred, &sin->sin_addr); if (error != 0) { INP_WUNLOCK(inp); @@ -1741,9 +1753,23 @@ udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct thread *td) { struct inpcb *inp; + int error; inp = sotoinpcb(so); KASSERT(inp != NULL, ("udp_send: inp == NULL")); + + if (addr != NULL) { + error = 0; + if (addr->sa_family != AF_INET) + error = EAFNOSUPPORT; + else if (addr->sa_len != sizeof(struct sockaddr_in)) + error = EINVAL; + if (__predict_false(error != 0)) { + m_freem(control); + m_freem(m); + return (error); + } + } return (udp_output(inp, m, addr, control, td, flags)); } #endif /* INET */ diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 5fce9fcafa33..1c36b4386030 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -146,13 +146,10 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, return (error); } else { sin6 = (struct sockaddr_in6 *)nam; - if (nam->sa_len != sizeof(*sin6)) - return (EINVAL); - /* - * family check. - */ - if (nam->sa_family != AF_INET6) - return (EAFNOSUPPORT); + KASSERT(sin6->sin6_family == AF_INET6, + ("%s: invalid address family for %p", __func__, sin6)); + KASSERT(sin6->sin6_len == sizeof(*sin6), + ("%s: invalid address length for %p", __func__, sin6)); if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0) return(error); @@ -345,10 +342,9 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, * have forced minor changes in every protocol). */ static int -in6_pcbladdr(struct inpcb *inp, struct sockaddr *nam, +in6_pcbladdr(struct inpcb *inp, struct sockaddr_in6 *sin6, struct in6_addr *plocal_addr6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; int error = 0; int scope_ambiguous = 0; struct in6_addr in6a; @@ -357,10 +353,6 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr *nam, INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo); /* XXXRW: why? */ - if (nam->sa_len != sizeof (*sin6)) - return (EINVAL); - if (sin6->sin6_family != AF_INET6) - return (EAFNOSUPPORT); if (sin6->sin6_port == 0) return (EADDRNOTAVAIL); @@ -421,6 +413,11 @@ in6_pcbconnect_mbuf(struct inpcb *inp, struct sockaddr *nam, struct sockaddr_in6 laddr6; int error; + KASSERT(sin6->sin6_family == AF_INET6, + ("%s: invalid address family for %p", __func__, sin6)); + KASSERT(sin6->sin6_len == sizeof(*sin6), + ("%s: invalid address length for %p", __func__, sin6)); + bzero(&laddr6, sizeof(laddr6)); laddr6.sin6_family = AF_INET6; @@ -442,7 +439,7 @@ in6_pcbconnect_mbuf(struct inpcb *inp, struct sockaddr *nam, * Call inner routine, to assign local interface address. * in6_pcbladdr() may automatically fill in sin6_scope_id. */ - if ((error = in6_pcbladdr(inp, nam, &laddr6.sin6_addr)) != 0) + if ((error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr)) != 0) return (error); if (in6_pcblookup_hash_locked(pcbinfo, &sin6->sin6_addr, diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 8d71c40455a1..3d2af6e5c9e6 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -760,6 +760,8 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip6_bind: inp == NULL")); + if (nam->sa_family != AF_INET6) + return (EAFNOSUPPORT); if (nam->sa_len != sizeof(*addr)) return (EINVAL); if ((error = prison_check_ip6(td->td_ucred, &addr->sin6_addr)) != 0) @@ -891,6 +893,10 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, m_freem(m); return (ENOTCONN); } + if (nam->sa_family != AF_INET6) { + m_freem(m); + return (EAFNOSUPPORT); + } if (nam->sa_len != sizeof(struct sockaddr_in6)) { m_freem(m); return (EINVAL); diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index fcf15e4f81bf..1030fe1bbb68 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -709,6 +709,27 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); return (EDESTADDRREQ); } + switch (addr->sa_family) { +#ifdef INET + case AF_INET: + if (addr->sa_len != sizeof(struct sockaddr_in)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); + return (EINVAL); + } + break; +#endif +#ifdef INET6 + case AF_INET6: + if (addr->sa_len != sizeof(struct sockaddr_in6)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); + return (EINVAL); + } + break; +#endif + default: + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); + return (EINVAL); + } #ifdef INET sin6 = (struct sockaddr_in6 *)addr; if (SCTP_IPV6_V6ONLY(inp)) { diff --git a/sys/netinet6/send.c b/sys/netinet6/send.c index 642529cc6beb..816f4d2b6541 100644 --- a/sys/netinet6/send.c +++ b/sys/netinet6/send.c @@ -233,6 +233,14 @@ send_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, __func__, so, V_send_so)); sendsrc = (struct sockaddr_send *)nam; + if (sendsrc->send_family != AF_INET6) { + error = EAFNOSUPPORT; + goto err; + } + if (sendsrc->send_len != sizeof(*sendsrc)) { + error = EINVAL; + goto err; + } ifp = ifnet_byindex_ref(sendsrc->send_ifidx); if (ifp == NULL) { error = ENETUNREACH; diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 3a001fea077d..7c573d095d77 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1091,6 +1091,11 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) inp = sotoinpcb(so); KASSERT(inp != NULL, ("udp6_bind: inp == NULL")); + if (nam->sa_family != AF_INET6) + return (EAFNOSUPPORT); + if (nam->sa_len != sizeof(struct sockaddr_in6)) + return (EINVAL); + INP_WLOCK(inp); INP_HASH_WLOCK(pcbinfo); vflagsav = inp->inp_vflag; @@ -1176,9 +1181,14 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); inp = sotoinpcb(so); - sin6 = (struct sockaddr_in6 *)nam; KASSERT(inp != NULL, ("udp6_connect: inp == NULL")); + sin6 = (struct sockaddr_in6 *)nam; + if (sin6->sin6_family != AF_INET6) + return (EAFNOSUPPORT); + if (sin6->sin6_len != sizeof(*sin6)) + return (EINVAL); + /* * XXXRW: Need to clarify locking of v4/v6 flags. */ diff --git a/sys/netipsec/keysock.c b/sys/netipsec/keysock.c index 49efa0a3c510..317eb53289cf 100644 --- a/sys/netipsec/keysock.c +++ b/sys/netipsec/keysock.c @@ -322,7 +322,7 @@ key_attach(struct socket *so, int proto, struct thread *td) static int key_bind(struct socket *so, struct sockaddr *nam, struct thread *td) { - return EINVAL; + return EINVAL; } /* diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c index e7ae4e03365e..a38bdfcbed59 100644 --- a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c @@ -519,9 +519,9 @@ sdp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) struct sockaddr_in *sin; sin = (struct sockaddr_in *)nam; - if (nam->sa_len != sizeof (*sin)) - return (EINVAL); if (sin->sin_family != AF_INET) + return (EAFNOSUPPORT); + if (nam->sa_len != sizeof(*sin)) return (EINVAL); if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return (EAFNOSUPPORT); @@ -617,10 +617,10 @@ sdp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) struct sockaddr_in *sin; sin = (struct sockaddr_in *)nam; - if (nam->sa_len != sizeof (*sin)) + if (nam->sa_len != sizeof(*sin)) return (EINVAL); if (sin->sin_family != AF_INET) - return (EINVAL); + return (EAFNOSUPPORT); if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return (EAFNOSUPPORT); if ((error = prison_remote_ip4(td->td_ucred, &sin->sin_addr)) != 0) @@ -932,6 +932,21 @@ sdp_send(struct socket *so, int flags, struct mbuf *m, int error; int cnt; + if (nam != NULL) { + if (nam->sa_family != AF_INET) { + if (control) + m_freem(control); + m_freem(m); + return (EAFNOSUPPORT); + } + if (nam->sa_len != sizeof(struct sockaddr_in)) { + if (control) + m_freem(control); + m_freem(m); + return (EINVAL); + } + } + error = 0; ssk = sdp_sk(so); KASSERT(m->m_flags & M_PKTHDR,