Fix CVE-2026-13204: assertion crash via unsigned NSEC/NSEC3

Add patch for CVE-2026-13204 which fixes a denial of service
vulnerability where dns_rdataset_addnoqname() could accept
unsigned NSEC/NSEC3 records, leading to assertion failures.
The upstream fix replaces RUNTIME_CHECK assertions with
graceful error handling in rbtdb.c, resolver.c, and query.c,
and hardens rdatalist.c to only accept signed records. The
patch includes an additional fix for query.c where the
upstream CHECK() macro was replaced with explicit inline
error handling to use the correct error label.

CVE: CVE-2026-13204
Upstream patches:
 - 48f5aa5fb3.patch
Resolves: RHEL-213494

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 10:37:47 +00:00 committed by Petr Menšík
parent 9777154579
commit 73495a511e
2 changed files with 183 additions and 1 deletions

View File

@ -0,0 +1,176 @@
From 5716f155883fb427cdccce0ef7ef9119dd40734e Mon Sep 17 00:00:00 2001
From: Evan Hunt <each@isc.org>
Date: Wed, 13 May 2026 20:45:57 -0700
Subject: [PATCH 1/2] 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 | 32 +++++++++++++++-----------------
lib/dns/resolver.c | 4 +++-
lib/ns/query.c | 3 +--
4 files changed, 26 insertions(+), 23 deletions(-)
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index c4db047ebe..06bc81da5d 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -6903,7 +6903,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
static 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;
@@ -6915,7 +6915,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);
@@ -6941,7 +6943,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 a2643c749f..8f9556a214 100644
--- a/lib/dns/rdatalist.c
+++ b/lib/dns/rdatalist.c
@@ -192,6 +192,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);
@@ -199,30 +200,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) {
- continue;
- }
- if (rdset->type == dns_rdatatype_nsec ||
- rdset->type == dns_rdatatype_nsec3)
+ if (rdset->rdclass != rdataset->rdclass ||
+ (rdset->type != dns_rdatatype_nsec &&
+ rdset->type != dns_rdatatype_nsec3))
{
- neg = rdset;
+ continue;
}
- }
- 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)
+ for (sigset = ISC_LIST_HEAD(name->list); sigset != NULL;
+ sigset = ISC_LIST_NEXT(sigset, link))
{
- negsig = rdset;
+ 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);
}
/*
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 9f0334c749..1f1e376ea7 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -5773,7 +5773,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 de1d65fcf1..2998f15a68 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -7890,8 +7890,7 @@ query_addnoqnameproof(query_ctx_t *qctx) {
goto cleanup;
}
- result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ CHECK(dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig));
query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
DNS_SECTION_AUTHORITY);
From 21f5bc38fd091006029d4a12c07fff426fd7b84a Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
Date: Thu, 23 Jul 2026 09:49:31 +0000
Subject: [PATCH 2/2] Fix CHECK macro usage in query_addnoqnameproof
Replace CHECK() macro call with inline error handling since CHECK
is not defined in query.c. The function uses 'cleanup' as its error
label, not 'failure' (which CHECK would jump to), so use explicit
result check with goto cleanup instead.
---
lib/ns/query.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/ns/query.c b/lib/ns/query.c
index 2998f15a68..2b2b027e59 100644
--- a/lib/ns/query.c
+++ b/lib/ns/query.c
@@ -7890,7 +7890,10 @@ query_addnoqnameproof(query_ctx_t *qctx) {
goto cleanup;
}
- CHECK(dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig));
+ result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
DNS_SECTION_AUTHORITY);

View File

@ -75,7 +75,7 @@ License: MPL-2.0 AND ISC AND MIT AND BSD-3-Clause AND BSD-2-Clause
# ./lib/isc/tm.c BSD-2-clause and/or MPL-2.0
# ./lib/isccfg/parser.c BSD-2-clause and/or MPL-2.0
Version: 9.18.29
Release: 17%{?dist}
Release: 18%{?dist}
Epoch: 32
Url: https://www.isc.org/downloads/bind/
#
@ -156,6 +156,8 @@ Patch233: bind-9.18-CVE-2026-1519-test.patch
Patch234: bind-9.18-CVE-2026-3039.patch
# https://gitlab.isc.org/isc-projects/bind9/-/commit/7ce6ce37b1b04af0953ed2d3211587465085600e
Patch235: bind-9.18-CVE-2026-5946.patch
# https://github.com/isc-projects/bind9/commit/48f5aa5fb3746d6194edcc57e8792a8b3cc3b454
Patch236: bind-9.18-CVE-2026-13204.patch
%{?systemd_ordering}
# https://fedoraproject.org/wiki/Changes/RPMSuportForSystemdSysusers
@ -1019,6 +1021,10 @@ fi;
%endif
%changelog
* Thu Jul 23 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 32:9.18.29-18
- Fix assertion crash via unsigned NSEC/NSEC3 (CVE-2026-13204,
RHEL-213495)
* Mon May 25 2026 Petr Menšík <pemensik@redhat.com> - 32:9.18.29-17
- Fix GSS-API resource leak (CVE-2026-3039)
- Invalid handling of CLASS != IN (CVE-2026-5946)