netinet: Tighten checks for unspecified source addresses

The assertions added in commit b0ccf53f24 ("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
This commit is contained in:
Mark Johnston 2023-03-06 15:06:00 -05:00
parent 1be25bdb73
commit 713264f6b8
4 changed files with 17 additions and 0 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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.