From cbe3a493d74da8309cfcc15abb592e8c7d0f18b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Thu, 23 Oct 2025 15:56:34 +0200 Subject: [PATCH] Prevent malformed DNSKEY to overload CPU (CVE-2025-8677) Unmodified upstream patches. https://kb.isc.org/docs/cve-2025-8677 Resolves: RHEL-123329 --- bind-9.18-CVE-2025-8677.patch | 223 ++++++++++++++++++++++++++++++++++ bind9.18.spec | 8 +- 2 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 bind-9.18-CVE-2025-8677.patch diff --git a/bind-9.18-CVE-2025-8677.patch b/bind-9.18-CVE-2025-8677.patch new file mode 100644 index 0000000..78c79c2 --- /dev/null +++ b/bind-9.18-CVE-2025-8677.patch @@ -0,0 +1,223 @@ +From c30c944e424a6c2281e0b1d53e25fc8ed3f71d41 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= +Date: Tue, 22 Jul 2025 08:07:02 +0200 +Subject: [PATCH] Fail the DNSSEC validation if matching but invalid DNSKEY is + found + +If a matching but cryptographically invalid key was encountered during +the DNSSEC validation, the key would be just skipped and not counted +towards validation failures. Treat such DNSSEC keys as hard failures +and fail the DNSSEC validation immediatelly instead of continuing the +DNSSEC validation with the next DNSKEYs in the RRset. + +Co-authored-by: Matthijs Mekking + +(cherry picked from commit f00117a4226be90d1bc865aff19bddf114242914) +(cherry picked from commit 7c5b8ef055900224f0424c341927562c5a9ebe19) + +Fix an issue with selfsigned_dnskey() return value + +The selfsigned_dnskey() function currently returns boolean. There +was a recent change to make it return a isc_result_t error code, +which is implicitly converted to bool, which is obviously an error. + +If instead of the result code we return true/false, it still doesn't +indicate the error to the caller that has happened before. + +Change the function to return isc_result_t, and change the caller +routine to process the new return type. + +(cherry picked from commit 40c396ba2d955c32d70db04e900e40bf96519c59) +--- + lib/dns/validator.c | 79 +++++++++++++++++++++++++++++---------------- + 1 file changed, 51 insertions(+), 28 deletions(-) + +diff --git a/lib/dns/validator.c b/lib/dns/validator.c +index 696a464..1d84b75 100644 +--- a/lib/dns/validator.c ++++ b/lib/dns/validator.c +@@ -431,6 +431,8 @@ fetch_callback_dnskey(isc_task_t *task, isc_event_t *event) { + result = select_signing_key(val, rdataset); + if (result == ISC_R_SUCCESS) { + val->keyset = &val->frdataset; ++ } else { ++ val->failed = true; + } + } + result = validate_answer(val, true); +@@ -1161,6 +1163,8 @@ select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) { + goto done; + } + dst_key_free(&val->key); ++ } else { ++ break; + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(rdataset); +@@ -1285,13 +1289,15 @@ seek_dnskey(dns_validator_t *val) { + "keyset with trust %s", + dns_trust_totext(val->frdataset.trust)); + result = select_signing_key(val, val->keyset); +- if (result != ISC_R_SUCCESS) { ++ if (result == ISC_R_NOTFOUND) { + /* +- * Either the key we're looking for is not +- * in the rrset, or something bad happened. +- * Give up. ++ * The key we're looking for is not ++ * in the rrset + */ + result = DNS_R_CONTINUE; ++ } else if (result != ISC_R_SUCCESS) { ++ /* Something bad happened. Give up. */ ++ break; + } + } + break; +@@ -1352,17 +1358,17 @@ compute_keytag(dns_rdata_t *rdata) { + /*% + * Is the DNSKEY rrset in val->event->rdataset self-signed? + */ +-static bool ++static isc_result_t + selfsigned_dnskey(dns_validator_t *val) { + dns_rdataset_t *rdataset = val->event->rdataset; + dns_rdataset_t *sigrdataset = val->event->sigrdataset; + dns_name_t *name = val->event->name; + isc_result_t result; + isc_mem_t *mctx = val->view->mctx; +- bool answer = false; ++ bool match = false; + + if (rdataset->type != dns_rdatatype_dnskey) { +- return (false); ++ return DNS_R_NOKEYMATCH; + } + + for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; +@@ -1384,8 +1390,6 @@ selfsigned_dnskey(dns_validator_t *val) { + result == ISC_R_SUCCESS; + result = dns_rdataset_next(sigrdataset)) + { +- dst_key_t *dstkey = NULL; +- + dns_rdata_reset(&sigrdata); + dns_rdataset_current(sigrdataset, &sigrdata); + result = dns_rdata_tostruct(&sigrdata, &sig, NULL); +@@ -1400,18 +1404,16 @@ selfsigned_dnskey(dns_validator_t *val) { + + /* + * If the REVOKE bit is not set we have a +- * theoretically self signed DNSKEY RRset. +- * This will be verified later. ++ * theoretically self-signed DNSKEY RRset; ++ * this will be verified later. ++ * ++ * We don't return the answer yet, though, ++ * because we need to check the remaining keys ++ * and possbly remove them if they're revoked. + */ + if ((key.flags & DNS_KEYFLAG_REVOKE) == 0) { +- answer = true; +- continue; +- } +- +- result = dns_dnssec_keyfromrdata(name, &keyrdata, mctx, +- &dstkey); +- if (result != ISC_R_SUCCESS) { +- continue; ++ match = true; ++ break; + } + + /* +@@ -1421,6 +1423,14 @@ selfsigned_dnskey(dns_validator_t *val) { + if (DNS_TRUST_PENDING(rdataset->trust) && + dns_view_istrusted(val->view, name, &key)) + { ++ dst_key_t *dstkey = NULL; ++ ++ result = dns_dnssec_keyfromrdata( ++ name, &keyrdata, mctx, &dstkey); ++ if (result != ISC_R_SUCCESS) { ++ break; ++ } ++ + result = dns_dnssec_verify( + name, rdataset, dstkey, true, + val->view->maxbits, mctx, &sigrdata, +@@ -1433,6 +1443,8 @@ selfsigned_dnskey(dns_validator_t *val) { + */ + dns_view_untrust(val->view, name, &key); + } ++ ++ dst_key_free(&dstkey); + } else if (rdataset->trust >= dns_trust_secure) { + /* + * We trust this RRset so if the key is +@@ -1440,12 +1452,14 @@ selfsigned_dnskey(dns_validator_t *val) { + */ + dns_view_untrust(val->view, name, &key); + } +- +- dst_key_free(&dstkey); + } + } + +- return (answer); ++ if (!match) { ++ return DNS_R_NOKEYMATCH; ++ } ++ ++ return ISC_R_SUCCESS; + } + + /*% +@@ -1680,10 +1694,7 @@ check_signer(dns_validator_t *val, dns_rdata_t *keyrdata, uint16_t keyid, + val->event->name, keyrdata, val->view->mctx, + &dstkey); + if (result != ISC_R_SUCCESS) { +- /* +- * This really shouldn't happen, but... +- */ +- continue; ++ return result; + } + } + result = verify(val, dstkey, &rdata, sig.keyid); +@@ -3064,11 +3075,22 @@ validator_start(isc_task_t *task, isc_event_t *event) { + + INSIST(dns_rdataset_isassociated(val->event->rdataset)); + INSIST(dns_rdataset_isassociated(val->event->sigrdataset)); +- if (selfsigned_dnskey(val)) { ++ ++ result = selfsigned_dnskey(val); ++ switch (result) { ++ case ISC_R_SUCCESS: + result = validate_dnskey(val); +- } else { ++ break; ++ case DNS_R_NOKEYMATCH: + result = validate_answer(val, false); ++ break; ++ default: ++ validator_log(val, ISC_LOG_INFO, ++ "invalid selfsigned DNSKEY: %s", ++ isc_result_totext(result)); ++ goto cleanup; + } ++ + if (result == DNS_R_NOVALIDSIG && + (val->attributes & VALATTR_TRIEDVERIFY) == 0) + { +@@ -3137,6 +3159,7 @@ validator_start(isc_task_t *task, isc_event_t *event) { + UNREACHABLE(); + } + ++cleanup: + if (result != DNS_R_WAIT) { + want_destroy = exit_check(val); + validator_done(val, result); +-- +2.51.1 + diff --git a/bind9.18.spec b/bind9.18.spec index 8b8b792..ae1a677 100644 --- a/bind9.18.spec +++ b/bind9.18.spec @@ -77,7 +77,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: 5%{?dist} +Release: 6%{?dist} Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -130,6 +130,9 @@ Patch32: bind-9.18-CVE-2024-12705.patch Patch33: bind-9.21-resume-qmin-cname.patch # downstream only, extra check for above change, RHEL-30407 Patch34: bind-9.18-query-fname-relative.patch +# https://gitlab.isc.org/isc-projects/bind9/commit/40c396ba2d955c32d70db04e900e40bf96519c59 +# https://gitlab.isc.org/isc-projects/bind9/commit/7c5b8ef055900224f0424c341927562c5a9ebe19 +Patch223: bind-9.18-CVE-2025-8677.patch %{?systemd_ordering} Requires: coreutils @@ -977,6 +980,9 @@ fi; %endif %changelog +* Thu Oct 23 2025 Petr Menšík - 32:9.18.29-6 +- Refuse malformed DNSKEY records (CVE-2025-8677) + * Fri Sep 12 2025 Petr Menšík - 32:9.18.29-5 - logrotate: skip if empty and remove old variants (RHEL-113942)