aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-03-21 18:18:10 +0000
committerMark Johnston <markj@FreeBSD.org>2021-03-24 13:27:59 +0000
commite4bdf7ac2a32ba1f2402e06360e476ec804210e7 (patch)
treeeec6a462ae6d7e19eaa9e0fdaafe1c3c266a36bd
parent7b3ff601f90415ba3da62b910aa8ea14a54bfae3 (diff)
downloadsrc-e4bdf7ac2a32ba1f2402e06360e476ec804210e7.tar.gz
src-e4bdf7ac2a32ba1f2402e06360e476ec804210e7.zip
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 (cherry picked from commit 1af332a7d8f86b6fcc1f0f575fe5b06021b54f4c)
-rw-r--r--usr.sbin/rtsold/rtsol.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/usr.sbin/rtsold/rtsol.c b/usr.sbin/rtsold/rtsol.c
index 30027fc65ac9..76756bfd8393 100644
--- a/usr.sbin/rtsold/rtsol.c
+++ b/usr.sbin/rtsold/rtsol.c
@@ -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;
}