summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-05-23 12:07:37 +0000
committerHauke Mehrtens2026-06-18 00:34:59 +0000
commit8637f4cbb15c56c69f9ac85c021d9624850cbabf (patch)
treec9c166a28f64c4856afc2dacc6cae78f123375d8
parentf6571a42f24c7151e99ece24afe97d718ec96d07 (diff)
downloadodhcpd-8637f4cbb15c56c69f9ac85c021d9624850cbabf.tar.gz
dhcpv6: reject undersized encapsulated DHCPv4 messages in 4o6 path
dhcpv6_4o6_query() passes the inner OPTION_DHCPV4_MSG payload straight to dhcpv4_handle_msg(), which immediately reads the BOOTP fixed header (op, htype, hlen, ..., cookie — the bytes before dhcp.options). On the normal DHCPv4 UDP socket those reads are safe because a BPF filter drops anything shorter than offsetof(options); on the 4o6 path that filter is bypassed and any olen >= 1 was accepted, allowing an out-of- bounds read past the option buffer. Reject the message here so we keep the same minimum-length guarantee the BPF filter provides on the native path. Assisted-by: Claude:claude-opus-4-7 Link: https://github.com/openwrt/odhcpd/pull/401 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> (cherry picked from commit d89caa59c00516d5b5803ed87a86204e4c992799)
-rw-r--r--src/dhcpv6.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index b4fea34..38f9c15 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -317,6 +317,19 @@ static ssize_t dhcpv6_4o6_query(uint8_t *buf, size_t buflen,
return -1;
}
+ /* dhcpv4_handle_msg() reads the full BOOTP fixed header (op, htype,
+ * hlen, hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr,
+ * chaddr, sname, file, cookie = offsetof(options) bytes) before
+ * parsing options. The normal DHCPv4 socket path enforces this via a
+ * BPF filter, but the DHCPv4-over-DHCPv6 path bypasses that filter,
+ * so validate the length here to prevent an out-of-bounds read on a
+ * truncated DHCPV4_MSG option. RFC7341 §7.1 defines the DHCPv4 Message
+ * option but mandates no minimum length, so this floor is ours. */
+ if (msgv4_len < offsetof(struct dhcpv4_message, options)) {
+ error("4o6: encapsulated DHCPv4 message too short (%u)", msgv4_len);
+ return -1;
+ }
+
// Dummy IPv4 address
memset(&addrv4, 0, sizeof(addrv4));
addrv4.sin_family = AF_INET;