aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-05-31 22:53:34 +0000
committerMark Johnston <markj@FreeBSD.org>2021-05-31 22:53:34 +0000
commitf96603b56f0f74fa52d8f1ef0be869fca7305b99 (patch)
treee4baf6ede470f5e3851bb7435198bf2727b906df
parent18f55c67f746f0ad12fe972328234d340a621df9 (diff)
downloadsrc-f96603b56f0f74fa52d8f1ef0be869fca7305b99.tar.gz
src-f96603b56f0f74fa52d8f1ef0be869fca7305b99.zip
tcp, udp: Permit binding with AF_UNSPEC if the address is INADDR_ANY
Prior to commit f161d294b we only checked the sockaddr length, but now we verify the address family as well. This breaks at least ttcp. Relax the check to avoid breaking compatibility too much: permit AF_UNSPEC if the address is INADDR_ANY. Fixes: f161d294b Reported by: Bakul Shah <bakul@iitbombay.org> Reviewed by: tuexen MFC after: 3 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D30539
-rw-r--r--sys/netinet/tcp_usrreq.c11
-rw-r--r--sys/netinet/udp_usrreq.c13
2 files changed, 20 insertions, 4 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index caef798772ea..7f1b698408e5 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -321,8 +321,15 @@ tcp_usr_bind(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_family != AF_INET) {
+ /*
+ * Preserve compatibility with old programs.
+ */
+ if (nam->sa_family != AF_UNSPEC ||
+ sinp->sin_addr.s_addr != INADDR_ANY)
+ return (EAFNOSUPPORT);
+ nam->sa_family = AF_INET;
+ }
if (nam->sa_len != sizeof(*sinp))
return (EINVAL);
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 62a07701df6c..5c9dbd36a1d6 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1622,14 +1622,23 @@ udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct inpcb *inp;
struct inpcbinfo *pcbinfo;
+ struct sockaddr_in *sinp;
int error;
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);
+ sinp = (struct sockaddr_in *)nam;
+ if (nam->sa_family != AF_INET) {
+ /*
+ * Preserve compatibility with old programs.
+ */
+ if (nam->sa_family != AF_UNSPEC ||
+ sinp->sin_addr.s_addr != INADDR_ANY)
+ return (EAFNOSUPPORT);
+ nam->sa_family = AF_INET;
+ }
if (nam->sa_len != sizeof(struct sockaddr_in))
return (EINVAL);