Fix CVE-2026-13204: ensure NSEC/NSEC3 has matching RRSIG

Backport upstream fix for CVE-2026-13204 to bind9.16. The patch
ensures that dns_rdataset_addnoqname() only accepts NSEC/NSEC3
records that have matching RRSIG signatures, preventing
acceptance of unsigned records. Additionally, callers in
resolver.c and query.c now handle non-success return codes
gracefully instead of triggering assertion failures.

CVE: CVE-2026-13204
Upstream patches:
 - 1b90fbb4f9.patch
Resolves: RHEL-213478

This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.

Assisted-by: Ymir
This commit is contained in:
RHEL Packaging Agent 2026-07-23 11:13:32 +00:00 committed by Petr Menšík
parent fc16ff66ec
commit 260a501b98
2 changed files with 162 additions and 1 deletions

View File

@ -0,0 +1,154 @@
From f22132f6faf946cfec02e9b51c58cab54695f42f Mon Sep 17 00:00:00 2001
From: Evan Hunt <each@isc.org>
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 a44ae73..b73c8e0 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -6010,7 +6010,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 4d6dd5d..673fe43 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -7399,7 +7399,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);

View File

@ -62,7 +62,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
Name: bind9.16
License: MPLv2.0
Version: 9.16.23
Release: 0.22%{?dist}.6
Release: 0.22%{?dist}.7
Epoch: 32
Url: https://www.isc.org/downloads/bind/
#
@ -187,6 +187,8 @@ Patch230: bind-9.16-CVE-2026-3039.patch
# https://gitlab.isc.org/isc-projects/bind9/-/commit/ec2c98181115bd5f6c7087fcc74d816490d4312e
# https://gitlab.isc.org/isc-projects/bind9/-/commit/e5abd37cb2330af1fbfeba68eb32f2873390226d
Patch231: bind-9.16-CVE-2026-5946.patch
# https://github.com/isc-projects/bind9/commit/1b90fbb4f9d3d923516ff7841171269b993cfd6f
Patch233: bind-9.16-CVE-2026-13204.patch
%{?systemd_ordering}
Requires: coreutils
@ -529,6 +531,7 @@ in HTML and PDF format.
%patch226 -p1 -b .CVE-2026-1519
%patch230 -p1 -b .CVE-2026-3039
%patch231 -p1 -b .CVE-2026-5946
%patch233 -p1 -b .CVE-2026-13204
%if %{with PKCS11}
%patch135 -p1 -b .config-pkcs11
@ -1271,6 +1274,10 @@ fi;
%endif
%changelog
* Thu Jul 23 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 32:9.16.23-0.22.7
- Fix CVE-2026-13204: ensure NSEC/NSEC3 has matching RRSIG
- Resolves: RHEL-213478
* Mon May 25 2026 Petr Menšík <pemensik@redhat.com> - 32:9.16.23-0.22.6
- Fix GSS-API resource leak (CVE-2026-3039)
- Invalid handling of CLASS != IN (CVE-2026-5946)