Fix CVE-2026-13204: prevent accepting unsigned NSEC/NSEC3 records

Backport upstream commit 204fde85 to fix CVE-2026-13204.
The dns_rdataset_addnoqname() function could accept unsigned
NSEC/NSEC3 records, causing an assertion failure. The fix
restructures the NSEC/NSEC3 search to require a matching RRSIG
signature and replaces RUNTIME_CHECK assertions with graceful
error handling in query.c, rbtdb.c, rdatalist.c, and
resolver.c.

CVE: CVE-2026-13204
Upstream patches:
 - 204fde8595.patch
Resolves: RHEL-213489

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-27 15:42:37 +00:00
parent 0f28e7dd60
commit cbdd087dd3
2 changed files with 161 additions and 1 deletions

View File

@ -0,0 +1,154 @@
From 0be245b5c7641533fff2f808d19730e9766a9a36 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)
---
bin/named/query.c | 4 +++-
lib/dns/rbtdb.c | 8 +++++---
lib/dns/rdatalist.c | 36 +++++++++++++++++++++---------------
lib/dns/resolver.c | 4 +++-
4 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/bin/named/query.c b/bin/named/query.c
index e023d74..083ce83 100644
--- a/bin/named/query.c
+++ b/bin/named/query.c
@@ -6198,7 +6198,9 @@ query_addnoqnameproof(ns_client_t *client, dns_rdataset_t *rdataset) {
goto cleanup;
result = dns_rdataset_getnoqname(rdataset, fname, neg, negsig);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
query_addrrset(client, &fname, &neg, &negsig, dbuf,
DNS_SECTION_AUTHORITY);
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index 388ffdf..b7f21ac 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -6977,7 +6977,7 @@ static inline isc_result_t
addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
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;
@@ -6989,7 +6989,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));
if (noqname == NULL) {
@@ -7021,7 +7023,7 @@ cleanup:
dns_rdataset_disassociate(&negsig);
if (noqname != NULL)
free_noqname(mctx, &noqname);
- return(result);
+ return (result);
}
static inline isc_result_t
diff --git a/lib/dns/rdatalist.c b/lib/dns/rdatalist.c
index cc2619c..687953c 100644
--- a/lib/dns/rdatalist.c
+++ b/lib/dns/rdatalist.c
@@ -196,6 +196,7 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, 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);
@@ -204,26 +205,30 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
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;
+ }
+
+ 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 (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;
+ if (neg == NULL || negsig == NULL) {
+ return (ISC_R_NOTFOUND);
}
- if (negsig == NULL)
- return (ISC_R_NOTFOUND);
/*
* Minimise ttl.
*/
@@ -235,6 +240,7 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, 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 5331ea9..78553f6 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -5153,7 +5153,9 @@ validated(isc_task_t *task, isc_event_t *event) {
if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
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) {

View File

@ -68,7 +68,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
Name: bind
License: MPLv2.0
Version: 9.11.36
Release: 16%{?PATCHVER:.%{PATCHVER}}%{?PREVER:.%{PREVER}}%{?dist}.11
Release: 16%{?PATCHVER:.%{PATCHVER}}%{?PREVER:.%{PREVER}}%{?dist}.12
Epoch: 32
Url: https://www.isc.org/downloads/bind/
#
@ -220,6 +220,8 @@ Patch219: bind-9.11-CVE-2026-11721.patch
# https://github.com/isc-projects/bind9/commit/058023c66f11d78590d4aa8c4f98946c4c965e21
# https://github.com/isc-projects/bind9/commit/f751e19a30d107f04c2f644aff9f8dab8fed03ab
Patch220: bind-9.11-CVE-2026-13321.patch
# https://github.com/isc-projects/bind9/commit/204fde85953d78475334694a7b9507dca47e73ba
Patch221: bind-9.11-CVE-2026-13204.patch
# SDB patches
Patch11: bind-9.3.2b2-sdbsrc.patch
@ -655,6 +657,7 @@ are used for building ISC DHCP.
%patch -P 218 -p1 -b .CVE-2026-11622
%patch -P 219 -p1 -b .CVE-2026-11721
%patch -P 220 -p1 -b .CVE-2026-13321
%patch -P 221 -p1 -b .CVE-2026-13204
mkdir lib/dns/tests/testdata/dstrandom
cp -a %{SOURCE50} lib/dns/tests/testdata/dstrandom/random.data
@ -1707,6 +1710,9 @@ rm -rf ${RPM_BUILD_ROOT}
%endif
%changelog
* Mon Jul 27 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 32:9.11.36-16.12
- Prevent accepting unsigned NSEC/NSEC3 records (CVE-2026-13204)
* Mon Jul 27 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 32:9.11.36-16.11
- Reject out-of-zone NSEC entries in DNSSEC validation
(CVE-2026-13321)