]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix CVE-2026-41292, Parsing a long list of incoming EDNS options
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 20 May 2026 08:18:23 +0000 (10:18 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 20 May 2026 08:18:23 +0000 (10:18 +0200)
  degrades performance. Thanks to GitHub user 'N0zoM1z0', also Qifan
  Zhang from Palo Alto Networks, for the report.

doc/Changelog
util/data/msgparse.c

index 66895692d4bff0095d07c37bcf9255516a6ba64f..c823bcbd2ae192333d8a9a39bb58ac1ea64fedbd 100644 (file)
@@ -10,6 +10,9 @@
          Griffiths from 'calif.io' for the report.
        - Fix CVE-2026-40622, "Ghost domain name" variant. Thanks to Qifan
          Zhang, Palo Alto Networks, for the report.
+       - Fix CVE-2026-41292, Parsing a long list of incoming EDNS options
+         degrades performance. Thanks to GitHub user 'N0zoM1z0', also Qifan
+         Zhang from Palo Alto Networks, for the report.
 
 23 April 2026: Wouter
        - Merge #1441: Fix buffer overrun in
index a38bed62ea27ce3712281693ff20418c71ea59ad..9239f8fe396a8dcf9cd6e321f8c86265354c081f 100644 (file)
@@ -53,6 +53,8 @@
 #include "sldns/parseutil.h"
 #include "sldns/wire2str.h"
 
+#define MAX_PARSED_EDNS_OPTIONS 100
+
 /** smart comparison of (compressed, valid) dnames from packet */
 static int
 smart_compare(sldns_buffer* pkt, uint8_t* dnow, 
@@ -950,7 +952,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
        struct comm_reply* repinfo, uint32_t now, struct regional* region,
        struct cookie_secrets* cookie_secrets)
 {
-       int nsid_seen = 0, cookie_seen = 0, padding_seen = 0;
+       int i = 0, nsid_seen = 0, cookie_seen = 0, padding_seen = 0;
        /* To respond with a Keepalive option, the client connection must have
         * received one message with a TCP Keepalive EDNS option, and that
         * option must have 0 length data. Subsequent messages sent on that
@@ -970,7 +972,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
 
        /* while still more options, and have code+len to read */
        /* ignores partial content (i.e. rdata len 3) */
-       while(rdata_len >= 4) {
+       while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) {
                uint16_t opt_code = sldns_read_uint16(rdata_ptr);
                uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
                uint8_t server_cookie[40];
@@ -1150,6 +1152,7 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
                }
                rdata_ptr += opt_len;
                rdata_len -= opt_len;
+               i++;
        }
        return LDNS_RCODE_NOERROR;
 }
@@ -1164,6 +1167,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
        struct rrset_parse* found_prev = 0;
        size_t rdata_len;
        uint8_t* rdata_ptr;
+       int i = 0;
        /* since the class encodes the UDP size, we cannot use hash table to
         * find the EDNS OPT record. Scan the packet. */
        while(rrset) {
@@ -1223,7 +1227,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
 
        /* while still more options, and have code+len to read */
        /* ignores partial content (i.e. rdata len 3) */
-       while(rdata_len >= 4) {
+       while(rdata_len >= 4 && i < MAX_PARSED_EDNS_OPTIONS) {
                uint16_t opt_code = sldns_read_uint16(rdata_ptr);
                uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
                rdata_ptr += 4;
@@ -1238,6 +1242,7 @@ parse_extract_edns_from_response_msg(struct msg_parse* msg,
                }
                rdata_ptr += opt_len;
                rdata_len -= opt_len;
+               i++;
        }
        /* ignore rrsigs */
        return LDNS_RCODE_NOERROR;