From: Ondřej Surý Date: Thu, 30 Apr 2026 12:12:50 +0000 (+0200) Subject: Bound EDNS option length in dig's process_opt() walk X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d0f69db898975ab571db2433849f33814c930dd;p=thirdparty%2Fbind9.git Bound EDNS option length in dig's process_opt() walk process_opt() reads the per-option (optcode, optlen) header from the OPT rdata and then advances the buffer by optlen, both for the COOKIE branch (via process_cookie()) and for any other optcode. The walk itself never compared optlen to the buffer remainder; the only reason it cannot trip the isc_buffer_forward() REQUIRE today is that fromwire_opt() (lib/dns/rdata/generic/opt_41.c) already validates each option's length against the rdata bounds before the rdataset is handed back, so process_opt() never sees a self-inconsistent rdata. That upstream guarantee is fine, but it leaves the local walker trusting an invariant established elsewhere. Add a defensive check that just stops the walk when a future caller (a cached message, an alternate parser, a refactor of the OPT validator) hands process_opt() a buffer where optlen would run past the end. Assisted-by: Claude:claude-opus-4-7 --- diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 145f9c93065..0ad6cd7d0ef 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -3805,6 +3805,9 @@ process_opt(dig_lookup_t *l, dns_message_t *msg) { while (isc_buffer_remaininglength(&optbuf) >= 4) { optcode = isc_buffer_getuint16(&optbuf); optlen = isc_buffer_getuint16(&optbuf); + if (optlen > isc_buffer_remaininglength(&optbuf)) { + break; + } switch (optcode) { case DNS_OPT_COOKIE: /*