]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix CVE-2026-42923, Degradation of service with unbounded NSEC3
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 20 May 2026 08:20:02 +0000 (10:20 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 20 May 2026 08:20:02 +0000 (10:20 +0200)
  hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.

doc/Changelog
validator/val_neg.c
validator/val_nsec3.c
validator/val_nsec3.h

index 03fa7ed3af88d193e464f9e69e9a1c26bf1e4ba5..4822075f9327588a8aa7d181c5b4e66f4f1f0e56 100644 (file)
@@ -16,6 +16,9 @@
        - Fix CVE-2026-42534, Jostle logic bypass degrades resolution
          performance. Thanks to Qifan Zhang, Palo Alto Networks, for the
          report.
+       - Fix CVE-2026-42923, Degradation of service with unbounded NSEC3
+         hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for
+         the report.
 
 23 April 2026: Wouter
        - Merge #1441: Fix buffer overrun in
index 66fd818994ed81e16b64c909501c088f9244b95a..e82f335b9ad960ffeb7d8c80b004567f76410a94 100644 (file)
 #include "sldns/rrdef.h"
 #include "sldns/sbuffer.h"
 
+/**
+ * The maximum salt length that the negative cache is willing to use.
+ * Larger salt increases the computation time, while recommendations are
+ * for zero salt length for zones.
+ */
+#define MAX_SALT_LENGTH 64
+
 int val_neg_data_compare(const void* a, const void* b)
 {
        struct val_neg_data* x = (struct val_neg_data*)a;
@@ -826,7 +833,11 @@ void neg_insert_data(struct val_neg_cache* neg,
                        (slen != 0 && zone->nsec3_salt && s
                          && memcmp(zone->nsec3_salt, s, slen) != 0))) {
 
-                       if(slen > 0) {
+                       if(slen > MAX_SALT_LENGTH) {
+                               /* RFC 9276 s3.1: operators SHOULD NOT use a salt; large
+                                * salts inflate per-hash block count. Decline to cache. */
+                               return;
+                       } else if(slen > 0) {
                                uint8_t* sa = memdup(s, slen);
                                if(sa) {
                                        free(zone->nsec3_salt);
@@ -1165,6 +1176,15 @@ neg_find_nsec3_ce(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
        uint8_t hashce[NSEC3_SHA_LEN];
        uint8_t b32[257];
        size_t celen, b32len;
+       int hashmax = MAX_NSEC3_CALCULATIONS;
+       if(qlabs > hashmax) {
+               /* strip leading labels so the walk costs at most
+                * MAX_NSEC3_CALCULATIONS hashes, mirroring val_nsec3.c */
+               while(qlabs > hashmax) {
+                       dname_remove_label(&qname, &qname_len);
+                       qlabs--;
+               }
+       }
 
        *nclen = 0;
        while(qlabs > 0) {
@@ -1265,6 +1285,12 @@ neg_nsec3_proof_ds(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
        if(!zone->nsec3_hash) 
                return NULL; /* not nsec3 zone */
 
+       if(!topname && qlabs > zone->labs + 1)
+               return NULL; /* iterator caller; opt-out proof would be discarded
+                            * at the !topname check below anyway.
+                            * The qlabs check allows the exact-match for
+                            * the one-label-below-zone case. */
+
        if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf,
                hashnc, &nclen))) {
                return NULL;
index 92d853825ddabc1ca56139153fd88fac9a000c7c..62effde2093fc3dcda7b1ec440008acc419cce4c 100644 (file)
 #include "sldns/sbuffer.h"
 #include "util/config_file.h"
 
-/**
- * Max number of NSEC3 calculations at once, suspend query for later.
- * 8 is low enough and allows for cases where multiple proofs are needed.
- */
-#define MAX_NSEC3_CALCULATIONS 8
 /**
  * When all allowed NSEC3 calculations at once resulted in error treat as
  * bogus. NSEC3 hash errors are not cached and this helps breaks loops with
index f668a270ff123ba8f18fdeeb1ae74d248c5f15ca..a13e92991106e5ec86e932b7b4c48070df0eef84 100644 (file)
@@ -98,6 +98,12 @@ struct sldns_buffer;
 /** The SHA1 hash algorithm for NSEC3 */
 #define NSEC3_HASH_SHA1        0x01
 
+/**
+ * Max number of NSEC3 calculations at once, suspend query for later.
+ * 8 is low enough and allows for cases where multiple proofs are needed.
+ */
+#define MAX_NSEC3_CALCULATIONS 8
+
 /**
 * Cache table for NSEC3 hashes.
 * It keeps a *pointer* to the region its items are allocated.