From 0630a45ae12d6175ccea88b3158b17886bfe5d85 Mon Sep 17 00:00:00 2001 From: Dominik Date: Thu, 19 Mar 2026 22:41:55 +0100 Subject: [PATCH] edns0: bounds-check option length before memcmp in check_source() The EDNS0 option iteration loop read a 2-byte len field from the packet and used it directly in: opt.scope_netmask = p[3]; // requires len >= 4 memcmp(p, &opt, len) // reads len bytes from packet Neither access was guarded against len exceeding the remaining RDATA. A crafted DNS reply whose OPT RDATA contains a CLIENT_SUBNET option with an oversized len field would cause memcmp to read past the end of the packet buffer, leaking heap memory. Risk: currently the only caller that reaches this branch is forward.c:process_reply(), which (before the companion fix) passed an OPT-RR-scoped plen that made skip_name() return NULL first, so the unsafe code was never reached. With that companion fix applied the path is live: a rogue upstream server or on-path attacker can craft a reply with a malformed CLIENT_SUBNET len and trigger the OOB read, potentially leaking adjacent heap contents. Fix: break out of the loop if the option body would extend past the RDATA boundary. Signed-off-by: Dominik --- src/edns0.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/edns0.c b/src/edns0.c index 5a5f598..71707fb 100644 --- a/src/edns0.c +++ b/src/edns0.c @@ -469,6 +469,8 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe { GETSHORT(code, p); GETSHORT(len, p); + if (i + 4 + len > rdlen) + break; /* malformed: option body extends beyond RDATA */ if (code == EDNS0_OPTION_CLIENT_SUBNET) { if (peer)