From 713264f6b8bc5f927dd52cf8ffcccfa397034fec Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Mon, 6 Mar 2023 15:06:00 -0500 Subject: [PATCH] netinet: Tighten checks for unspecified source addresses The assertions added in commit b0ccf53f2455 ("inpcb: Assert against wildcard addrs in in_pcblookup_hash_locked()") revealed that protocol layers may pass the unspecified address to in_pcblookup(). Add some checks to filter out such packets before we attempt an inpcb lookup: - Disallow the use of an unspecified source address in in_pcbladdr() and in6_pcbladdr(). - Disallow IP packets with an unspecified destination address. - Disallow TCP packets with an unspecified source address, and add an assertion to verify the comment claiming that the case of an unspecified destination address is handled by the IP layer. Reported by: syzbot+9ca890fb84e984e82df2@syzkaller.appspotmail.com Reported by: syzbot+ae873c71d3c71d5f41cb@syzkaller.appspotmail.com Reported by: syzbot+e3e689aba1d442905067@syzkaller.appspotmail.com Reviewed by: glebius, melifaro MFC after: 2 weeks Sponsored by: Klara, Inc. Sponsored by: Modirum MDPay Differential Revision: https://reviews.freebsd.org/D38570 --- sys/netinet/in_pcb.c | 2 ++ sys/netinet/ip_input.c | 5 +++++ sys/netinet/tcp_input.c | 8 ++++++++ sys/netinet6/in6_pcb.c | 2 ++ 4 files changed, 17 insertions(+) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 5768979f21e..3b8931a9026 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1262,6 +1262,8 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, } done: + if (error == 0 && laddr->s_addr == INADDR_ANY) + return (EHOSTUNREACH); return (error); } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index b8fb3861c5b..5de09a32a2f 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -519,6 +519,11 @@ ip_input(struct mbuf *m) goto bad; } } + /* The unspecified address can appear only as a src address - RFC1122 */ + if (__predict_false(ntohl(ip->ip_dst.s_addr) == INADDR_ANY)) { + IPSTAT_INC(ips_badaddr); + goto bad; + } if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 72faf53299e..7b9c5668e88 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -672,6 +672,8 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port) * Note that packets with unspecified IPv6 destination is * already dropped in ip6_input. */ + KASSERT(!IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst), + ("%s: unspecified destination v6 address", __func__)); if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { /* XXX stat */ goto drop; @@ -740,6 +742,12 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port) TCPSTAT_INC(tcps_rcvbadsum); goto drop; } + KASSERT(ip->ip_dst.s_addr != INADDR_ANY, + ("%s: unspecified destination v4 address", __func__)); + if (__predict_false(ip->ip_src.s_addr == INADDR_ANY)) { + /* XXX stat */ + goto drop; + } } #endif /* INET */ diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 8b1f97f322e..81a3fd49a93 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -368,6 +368,8 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr_in6 *sin6, inp, inp->inp_cred, scope_ambiguous, &in6a, NULL); if (error) return (error); + if (IN6_IS_ADDR_UNSPECIFIED(&in6a)) + return (EHOSTUNREACH); /* * Do not update this earlier, in case we return with an error.