]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Bound EDNS option length in dig's process_opt() walk 11937/head
authorOndřej Surý <ondrej@isc.org>
Thu, 30 Apr 2026 12:12:50 +0000 (14:12 +0200)
committerOndřej Surý <ondrej@isc.org>
Fri, 1 May 2026 05:19:49 +0000 (07:19 +0200)
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
bin/dig/dighost.c

index 145f9c930655efd711a0721d8fc38e0b99601309..0ad6cd7d0ef1f84f9526f54eb6b2a1bb29e36828 100644 (file)
@@ -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:
                                /*