]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Stop leaking DNSSEC keys past the zone key limit
authorOndřej Surý <ondrej@isc.org>
Mon, 29 Jun 2026 06:48:03 +0000 (08:48 +0200)
committerMark Andrews <marka@isc.org>
Wed, 1 Jul 2026 06:45:56 +0000 (16:45 +1000)
find_zone_keys() collects every matching private key into a local list,
hands the first DNS_MAXZONEKEYS keys to the caller, and frees the rest.
On overflow it destroyed only the first surplus key before breaking out
of the loop, so any keys after it stayed linked on the local list and
were lost when the function returned.

Unlink and destroy every list entry, transferring a key to the caller
only while under the limit.  No entry is left behind, so a zone with
more than DNS_MAXZONEKEYS matching keys no longer leaks memory on each
signing attempt.

lib/dns/update.c

index 528ccd2898f505b753797875802ecbd94eac9c72..c8e6542d139f6f1b735110b033c68854809538dd 100644 (file)
@@ -932,26 +932,25 @@ find_zone_keys(dns_zone_t *zone, isc_mem_t *mctx, unsigned int maxkeys,
 
        /* Add new 'dnskeys' to 'keys' */
        ISC_LIST_FOREACH(keylist, k, link) {
-               if (count >= maxkeys) {
-                       ISC_LIST_UNLINK(keylist, k, link);
-                       dns_dnsseckey_destroy(mctx, &k);
-                       result = ISC_R_NOSPACE;
-                       break;
-               }
+               if (count < maxkeys) {
+                       /* Detect inactive keys */
+                       if (!dns_dnssec_keyactive(k->key, now)) {
+                               dst_key_setinactive(k->key, true);
+                       }
 
-               /* Detect inactive keys */
-               if (!dns_dnssec_keyactive(k->key, now)) {
-                       dst_key_setinactive(k->key, true);
+                       keys[count] = k->key;
+                       k->key = NULL;
+                       count++;
                }
 
-               keys[count] = k->key;
-               k->key = NULL;
-               count++;
-
                ISC_LIST_UNLINK(keylist, k, link);
                dns_dnsseckey_destroy(mctx, &k);
        }
 
+       if (count >= maxkeys) {
+               result = ISC_R_NOSPACE;
+       }
+
        *nkeys = count;
        return result;
 }