From e59f9329681051fbb4b320064804756061101139 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 13 May 2026 20:45:57 -0700 Subject: [PATCH] dns_rdataset_addnoqname() could find unsigned NSEC/NSEC3 The dns_rdatalist addnoqname() implementation searches for the first NSEC or NSEC3 record in a message, then for the first RRSIG covering that type in the same message. Previously, if no RRSIG for the type was found, the function accepted the unsigned record. Now, it will instead continue searching until an NSEC or NSEC3 that does have a matching signature is found. When this function is called from validated() in resolver.c, a non-success return code is now treated as an error instead of triggering an assertion failure. Fixes: isc-projects/bind9#5985 (cherry picked from commit 57cba571ee31311e54d8a11cb38094d439f04e09) --- lib/dns/rbtdb.c | 10 +++++++--- lib/dns/rdatalist.c | 33 +++++++++++++++++---------------- lib/dns/resolver.c | 4 +++- lib/ns/query.c | 4 +++- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 7586e2a..ae478bf 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -6877,7 +6877,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, static inline isc_result_t addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader, uint32_t maxrrperset, dns_rdataset_t *rdataset) { - struct noqname *noqname; + struct noqname *noqname = NULL; isc_mem_t *mctx = rbtdb->common.mctx; dns_name_t name; dns_rdataset_t neg, negsig; @@ -6889,7 +6889,9 @@ addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader, dns_rdataset_init(&negsig); result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } noqname = isc_mem_get(mctx, sizeof(*noqname)); dns_name_init(&noqname->name, NULL); @@ -6915,7 +6917,9 @@ addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader, cleanup: dns_rdataset_disassociate(&neg); dns_rdataset_disassociate(&negsig); - free_noqname(mctx, &noqname); + if (noqname != NULL) { + free_noqname(mctx, &noqname); + } return (result); } diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c index 9080015..cc0d190 100644 --- a/lib/dns/rdatalist.c +++ b/lib/dns/rdatalist.c @@ -190,6 +190,7 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name) { dns_rdataset_t *neg = NULL; dns_rdataset_t *negsig = NULL; dns_rdataset_t *rdset; + dns_rdataset_t *sigset; dns_ttl_t ttl; REQUIRE(rdataset != NULL); @@ -197,28 +198,27 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name) { for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL; rdset = ISC_LIST_NEXT(rdset, link)) { - if (rdset->rdclass != rdataset->rdclass) { + if (rdset->rdclass != rdataset->rdclass || + (rdset->type != dns_rdatatype_nsec && + rdset->type != dns_rdatatype_nsec3)) + { continue; } - if (rdset->type == dns_rdatatype_nsec || - rdset->type == dns_rdatatype_nsec3) { - neg = rdset; - } - } - if (neg == NULL) { - return (ISC_R_NOTFOUND); - } - for (rdset = ISC_LIST_HEAD(name->list); rdset != NULL; - rdset = ISC_LIST_NEXT(rdset, link)) - { - if (rdset->type == dns_rdatatype_rrsig && - rdset->covers == neg->type) { - negsig = rdset; + for (sigset = ISC_LIST_HEAD(name->list); sigset != NULL; + sigset = ISC_LIST_NEXT(sigset, link)) + { + if (sigset->type == dns_rdatatype_rrsig && + sigset->covers == rdset->type) + { + neg = rdset; + negsig = sigset; + break; + } } } - if (negsig == NULL) { + if (neg == NULL || negsig == NULL) { return (ISC_R_NOTFOUND); } /* @@ -234,6 +234,7 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name) { rdataset->ttl = neg->ttl = negsig->ttl = ttl; rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; rdataset->private6 = name; + return (ISC_R_SUCCESS); } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 460a15e..5635ff5 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -6019,7 +6019,9 @@ validated(isc_task_t *task, isc_event_t *event) { result = dns_rdataset_addnoqname( vevent->rdataset, vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]); - RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) { + goto noanswer_response; + } INSIST(vevent->sigrdataset != NULL); vevent->sigrdataset->ttl = vevent->rdataset->ttl; if (vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER] != NULL) { diff --git a/lib/ns/query.c b/lib/ns/query.c index 37893e2..96ddebd 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -7445,7 +7445,9 @@ query_addnoqnameproof(query_ctx_t *qctx) { } result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig); - RUNTIME_CHECK(result == ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } query_addrrset(qctx, &fname, &neg, &negsig, dbuf, DNS_SECTION_AUTHORITY);