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:
parent
9777154579
commit
73495a511e
176
bind-9.18-CVE-2026-13204.patch
Normal file
176
bind-9.18-CVE-2026-13204.patch
Normal 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);
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user