]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix memory leak in QPcache addnoqname/addclosest mechanism
authorOndřej Surý <ondrej@isc.org>
Tue, 10 Feb 2026 15:16:25 +0000 (16:16 +0100)
committerMichał Kępień <michal@isc.org>
Fri, 13 Mar 2026 12:22:23 +0000 (13:22 +0100)
The attacker that controls DNSSEC-signed zone can trigger a memory leak
in the addnoqname() and/or addclosest() by creating more than
max-records-per-type RRSIG for any NSEC records.  The memory leaks have
been fixed.

(cherry picked from commit a854a5c83d3a8556d31df880d22e3f835527d45d)

lib/dns/qpcache.c
lib/dns/rbtdb.c

index 8ceb23acc7097cdd87bcd1718734d693d4523064..1969d2116f5e045fade332d22240a4bf9b4e76f2 100644 (file)
@@ -3279,7 +3279,7 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        dns_slabheader_proof_t *noqname = NULL;
        dns_name_t name = DNS_NAME_INITEMPTY;
        dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
-       isc_region_t r1, r2;
+       isc_region_t r1 = { .base = NULL }, r2 = { .base = NULL };
 
        result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -3305,6 +3305,14 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        newheader->noqname = noqname;
 
 cleanup:
+       if (result != ISC_R_SUCCESS) {
+               if (r1.base != NULL) {
+                       isc_mem_put(mctx, r1.base, r1.length);
+               }
+               if (r2.base != NULL) {
+                       isc_mem_put(mctx, r2.base, r2.length);
+               }
+       }
        dns_rdataset_disassociate(&neg);
        dns_rdataset_disassociate(&negsig);
 
@@ -3318,7 +3326,7 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        dns_slabheader_proof_t *closest = NULL;
        dns_name_t name = DNS_NAME_INITEMPTY;
        dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
-       isc_region_t r1, r2;
+       isc_region_t r1 = { .base = NULL }, r2 = { .base = NULL };
 
        result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -3344,6 +3352,14 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        newheader->closest = closest;
 
 cleanup:
+       if (result != ISC_R_SUCCESS) {
+               if (r1.base != NULL) {
+                       isc_mem_put(mctx, r1.base, r1.length);
+               }
+               if (r2.base != NULL) {
+                       isc_mem_put(mctx, r2.base, r2.length);
+               }
+       }
        dns_rdataset_disassociate(&neg);
        dns_rdataset_disassociate(&negsig);
        return result;
index 2abaab290121d674125d6fb681ce51c83c9ae64d..386b8629242b111ed7a9890837bcaf4369bfef8c 100644 (file)
@@ -3180,7 +3180,7 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        dns_slabheader_proof_t *noqname = NULL;
        dns_name_t name = DNS_NAME_INITEMPTY;
        dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
-       isc_region_t r1, r2;
+       isc_region_t r1 = { .base = NULL }, r2 = { .base = NULL };
 
        result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -3206,6 +3206,14 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        newheader->noqname = noqname;
 
 cleanup:
+       if (result != ISC_R_SUCCESS) {
+               if (r1.base != NULL) {
+                       isc_mem_put(mctx, r1.base, r1.length);
+               }
+               if (r2.base != NULL) {
+                       isc_mem_put(mctx, r2.base, r2.length);
+               }
+       }
        dns_rdataset_disassociate(&neg);
        dns_rdataset_disassociate(&negsig);
 
@@ -3219,7 +3227,7 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        dns_slabheader_proof_t *closest = NULL;
        dns_name_t name = DNS_NAME_INITEMPTY;
        dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT;
-       isc_region_t r1, r2;
+       isc_region_t r1 = { .base = NULL }, r2 = { .base = NULL };
 
        result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig);
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
@@ -3245,6 +3253,14 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset,
        newheader->closest = closest;
 
 cleanup:
+       if (result != ISC_R_SUCCESS) {
+               if (r1.base != NULL) {
+                       isc_mem_put(mctx, r1.base, r1.length);
+               }
+               if (r2.base != NULL) {
+                       isc_mem_put(mctx, r2.base, r2.length);
+               }
+       }
        dns_rdataset_disassociate(&neg);
        dns_rdataset_disassociate(&negsig);
        return result;