rtsold: Fix validation of RDNSS options

The header specifies the size of the option in multiples of eight bytes.
The option consists of an eight-byte header followed by one or more IPv6
addresses, so the option is invalid if the size is not equal to 1+2n for
some n>0.  Check this.

The bug can cause random stack data to be formatted as an IPv6 address
and passed to resolvconf(8), but a host able to trigger the bug may also
specify arbitrary addresses this way.

Reported by:	Q C <cq674350529@gmail.com>
Sponsored by:	The FreeBSD Foundation
MFC after:	3 days
This commit is contained in:
Mark Johnston 2021-03-21 14:18:10 -04:00
parent 2476178e6b
commit 1af332a7d8

View file

@ -363,13 +363,19 @@ rtsol_input(int sock)
case ND_OPT_RDNSS:
rdnss = (struct nd_opt_rdnss *)raoptp;
/* Optlen sanity check (Section 5.3.1 in RFC 6106) */
if (rdnss->nd_opt_rdnss_len < 3) {
/*
* The option header is 8 bytes long and each address
* occupies 16 bytes, so the option length must be
* greater than or equal to 24 bytes and an odd multiple
* of 8 bytes. See section 5.1 in RFC 6106.
*/
if (rdnss->nd_opt_rdnss_len < 3 ||
rdnss->nd_opt_rdnss_len % 2 == 0) {
warnmsg(LOG_INFO, __func__,
"too short RDNSS option"
"in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, sizeof(ntopbuf)));
"too short RDNSS option in RA from %s "
"was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf,
sizeof(ntopbuf)));
break;
}