new file mode 100644
@@ -0,0 +1,283 @@
+From: Colin Vidal <colin@isc.org>
+Date: Thu, 18 Jun 2026 18:17:05 +0200
+Subject: Do not assert in some CNAME/DNAME queries
+
+Fix a `named` crash because of a fail assertion for certains types of
+CNAME and DNAME queries:
+
+- If a client queries for a DNAME and A record to the resolver, and the
+ authoritative server responds positively to the A query but delay the
+ DNAME response and respond later negatively;
+
+- If a client queries for a CNAME and A record to the resolver, and the
+ authoritative server responds positively to the A query but delay the
+ CNAME response and respond later with a self-referential CNAME.
+
+The first scenario consists of sending two queries: `foo.test./DNAME`
+and `a.foo.test./A`. The authoritative server delays the answer for
+`foo.test./DNAME` but immediately answers the DNAME record for the
+second query: `foo.test. DNAME bar.test.`. The resolver caches it,
+follows the DNAME, and resolves `a.bar.test./A`. The authoritative
+server eventually answers negatively for `foo.test./DNAME`
+(NOERROR/NODATA, with only an SOA in the authority section). The
+resolver pulls out the previously cached rdataset (because it has a
+higher trust level than the received negative answer), and wrongly (this
+is the first bug) sets the result to `DNS_R_DNAME` instead of
+`ISC_R_SUCCESS`. The code in `ns/query.c` that handles the resolver
+result interprets this as "this is a non-DNAME query and we got a DNAME
+rdataset, so follow the chain". It goes into the `query_dname()`
+function, which asserts that the qname is a subdomain of the owner name
+in the rdataset. That assertion fails because the qname (`foo.test.`) is
+exactly equal to the owner name of the DNAME (`foo.test.`), rather than
+being a subdomain of it. `DNS_R_DNAME` must only be set when the qtype
+is something other than DNAME and the resolver has obtained a DNAME that
+needs to be followed.
+
+The second scenario consists of sending two queries:
+`cname.foo.test./CNAME` and `cname.foo.test./A`. The authoritative
+server delays the answer for `cname.foo.test./CNAME` but immediately
+answers the CNAME record for the second query: `cname.foo.test. CNAME
+cname.foo.test.`. Note that the CNAME is self-referential. The resolver
+caches it and sets the result code to `DNS_R_CNAME`. Then `ns/query.c`
+interprets this as "this is a non-CNAME query and we got a CNAME
+rdataset, so follow the chain" (which is correct in this case; however,
+because the CNAME rdataset is self-referential, the resolver responds
+with SERVFAIL, which is expected). The authoritative server eventually
+answers negatively for `cname.foo.test./CNAME`. The resolver then pulls
+out the previously cached CNAME rdataset (obtained from the A answer,
+even though it was self-referential, the resolver cached it) and wrongly
+sets the result to `DNS_R_CNAME` (this is the second bug). As noted
+above, `ns/query.c` interprets this as "this is a non-CNAME query and we
+got a CNAME rdataset, so follow the chain". The internals here are
+slightly more subtle: it first goes into `query_cname()` and sets the
+CNAME rdataset in the message answer section, then restarts the query to
+follow the CNAME. The restart retrieves the CNAME rdataset from the
+cache directly (without going to the resolver), and this time the query
+context result is `ISC_R_SUCCESS` (since it was found) and
+`qctx->rdataset` points to the same CNAME again (as it is
+self-referential), so it goes directly into the
+`query_prepresponse()/query_respond()` flow, which attempts to add the
+rdataset to the message answer again. However, this fails because the
+rdataset is already in the message, and the assertion which expects that
+operation to succeed fails (due to `qctx->rdataset` being set to `NULL`
+when ownership of the rdataset was transferred). `DNS_R_CNAME` must only
+be set when the qtype is something other than CNAME and the resolver has
+obtained a CNAME that needs to be followed.
+
+In both cases, the correct answer from the resolver should have been
+`ISC_R_SUCCESS` (instead of respectively `DNS_R_DNAME` and
+`DNS_R_CNAME`) becuase the rdataset that has been looked up was found.
+
+(cherry picked from commit 773d46d58c693047a5945c8fe40512edd0ac214e)
+
+Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/c740c37689f234e21a9b0ef760471ef2cf1133f5
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-12617
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-12617
+
+CVE: CVE-2026-12617
+Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/c740c37689f234e21a9b0ef760471ef2cf1133f5]
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ lib/dns/resolver.c | 137 +++++++++++++++++++++++------------------------------
+ 1 file changed, 60 insertions(+), 77 deletions(-)
+
+diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
+index 9d46126..06c779e 100644
+--- a/lib/dns/resolver.c
++++ b/lib/dns/resolver.c
+@@ -692,10 +692,10 @@ fctx_destroy(fetchctx_t *fctx, bool exiting);
+ static void
+ send_shutdown_events(dns_resolver_t *res);
+ static isc_result_t
+-ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
+- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
+- dns_ttl_t maxttl, bool optout, bool secure,
+- dns_rdataset_t *ardataset, isc_result_t *eresultp);
++ncache_adderesult(fetchctx_t *fctx, dns_message_t *message, dns_dbnode_t *node,
++ dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
++ bool optout, bool secure, dns_rdataset_t *ardataset,
++ isc_result_t *eresultp);
+ static void
+ validated(isc_task_t *task, isc_event_t *event);
+ static void
+@@ -5580,6 +5580,46 @@ has_000_label(dns_rdataset_t *nsecset) {
+ return false;
+ }
+
++/*
++ * After a (non-error) negative-cache add, 'rdataset' is bound to whatever
++ * rdataset the cache authoritatively holds for the queried name and type.
++ * Map that to the result code the fetch should report:
++ *
++ * - A negative cache entry (the one we just added, or a pre-existing one):
++ * DNS_R_NCACHENXDOMAIN or DNS_R_NCACHENXRRSET, depending on NXDOMAIN vs
++ * NODATA.
++ *
++ * - A positive rdataset that was already cached at higher trust, which
++ * caused our negative entry to be discarded (e.g. a CNAME or DNAME cached
++ * by a concurrent query): ISC_R_SUCCESS, because that cached positive
++ * answer is what gets returned. Note the specific case for CNAME and
++ * DNAME *if* the query type is not the same as the rdataset type. There
++ * is a chain to follow *only* if the query type doesn't ask for the CNAME
++ * or the DNAME.
++ */
++static isc_result_t
++fctx_setresult(fetchctx_t *fctx, dns_rdataset_t *rdataset) {
++ isc_result_t result = ISC_R_SUCCESS;
++
++ if (NEGATIVE(rdataset)) {
++ result = NXDOMAIN(rdataset) ? DNS_R_NCACHENXDOMAIN
++ : DNS_R_NCACHENXRRSET;
++ } else if (result == ISC_R_SUCCESS && rdataset->type != fctx->type) {
++ switch (rdataset->type) {
++ case dns_rdatatype_cname:
++ result = DNS_R_CNAME;
++ break;
++ case dns_rdatatype_dname:
++ result = DNS_R_DNAME;
++ break;
++ default:
++ break;
++ }
++ }
++
++ return result;
++}
++
+ /*
+ * The validator has finished.
+ */
+@@ -5853,8 +5893,7 @@ validated(isc_task_t *task, isc_event_t *event) {
+ ttl = 0;
+ }
+
+- result = ncache_adderesult(message, fctx->cache, node, covers,
+- now, fctx->res->view->minncachettl,
++ result = ncache_adderesult(fctx, message, node, covers, now,
+ ttl, vevent->optout, vevent->secure,
+ ardataset, &eresult);
+ if (result != ISC_R_SUCCESS) {
+@@ -6098,23 +6137,7 @@ answer_response:
+ */
+ INSIST(hevent->rdataset != NULL);
+ if (dns_rdataset_isassociated(hevent->rdataset)) {
+- if (NEGATIVE(hevent->rdataset)) {
+- INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
+- eresult == DNS_R_NCACHENXRRSET);
+- } else if (eresult == ISC_R_SUCCESS &&
+- hevent->rdataset->type != fctx->type)
+- {
+- switch (hevent->rdataset->type) {
+- case dns_rdatatype_cname:
+- eresult = DNS_R_CNAME;
+- break;
+- case dns_rdatatype_dname:
+- eresult = DNS_R_DNAME;
+- break;
+- default:
+- break;
+- }
+- }
++ eresult = fctx_setresult(fctx, hevent->rdataset);
+ }
+
+ hevent->result = eresult;
+@@ -6764,24 +6787,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_message_t *message,
+ * event->result.
+ */
+ if (dns_rdataset_isassociated(event->rdataset)) {
+- if (NEGATIVE(event->rdataset)) {
+- INSIST(eresult ==
+- DNS_R_NCACHENXDOMAIN ||
+- eresult == DNS_R_NCACHENXRRSET);
+- } else if (eresult == ISC_R_SUCCESS &&
+- event->rdataset->type != fctx->type)
+- {
+- switch (event->rdataset->type) {
+- case dns_rdatatype_cname:
+- eresult = DNS_R_CNAME;
+- break;
+- case dns_rdatatype_dname:
+- eresult = DNS_R_DNAME;
+- break;
+- default:
+- break;
+- }
+- }
++ eresult = fctx_setresult(fctx, event->rdataset);
+ }
+ event->result = eresult;
+ if (adbp != NULL && *adbp != NULL) {
+@@ -6850,12 +6856,14 @@ cache_message(fetchctx_t *fctx, dns_message_t *message,
+ * eresult.
+ */
+ static isc_result_t
+-ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
+- dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
+- dns_ttl_t maxttl, bool optout, bool secure,
+- dns_rdataset_t *ardataset, isc_result_t *eresultp) {
++ncache_adderesult(fetchctx_t *fctx, dns_message_t *message, dns_dbnode_t *node,
++ dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
++ bool optout, bool secure, dns_rdataset_t *ardataset,
++ isc_result_t *eresultp) {
+ isc_result_t result;
+ dns_rdataset_t rdataset;
++ dns_db_t *cache = fctx->cache;
++ dns_ttl_t minttl = fctx->res->view->minncachettl;
+
+ if (ardataset == NULL) {
+ dns_rdataset_init(&rdataset);
+@@ -6871,37 +6879,13 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
+ }
+ if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
+ /*
+- * If the cache now contains a negative entry and we
+- * care about whether it is DNS_R_NCACHENXDOMAIN or
+- * DNS_R_NCACHENXRRSET then extract it.
++ * The cache settled successfully (DNS_R_UNCHANGED means our
++ * negative entry was discarded in favour of existing
++ * higher-trust data). Either way 'ardataset' is now bound to
++ * the rdataset the cache holds for this name and type; derive
++ * the result code from it.
+ */
+- if (NEGATIVE(ardataset)) {
+- /*
+- * The cache data is a negative cache entry.
+- */
+- if (NXDOMAIN(ardataset)) {
+- *eresultp = DNS_R_NCACHENXDOMAIN;
+- } else {
+- *eresultp = DNS_R_NCACHENXRRSET;
+- }
+- } else {
+- /*
+- * The attempt to add a negative cache entry
+- * was rejected. Set *eresultp to reflect
+- * the type of the dataset being returned.
+- */
+- switch (ardataset->type) {
+- case dns_rdatatype_cname:
+- *eresultp = DNS_R_CNAME;
+- break;
+- case dns_rdatatype_dname:
+- *eresultp = DNS_R_DNAME;
+- break;
+- default:
+- *eresultp = ISC_R_SUCCESS;
+- break;
+- }
+- }
++ *eresultp = fctx_setresult(fctx, ardataset);
+ result = ISC_R_SUCCESS;
+ }
+ if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset)) {
+@@ -7046,8 +7030,7 @@ ncache_message(fetchctx_t *fctx, dns_message_t *message,
+ ttl = 0;
+ }
+
+- result = ncache_adderesult(message, fctx->cache, node, covers, now,
+- fctx->res->view->minncachettl, ttl, false,
++ result = ncache_adderesult(fctx, message, node, covers, now, ttl, false,
+ false, ardataset, &eresult);
+ if (result != ISC_R_SUCCESS) {
+ goto unlock;
new file mode 100644
@@ -0,0 +1,292 @@
+From: Colin Vidal <colin@isc.org>
+Date: Mon, 15 Jun 2026 11:34:08 +0200
+Subject: Reproducer for #5946 (assertion in some CNAME/DNAME queries)
+
+Add a system test reproducing the issue reported by #5946, which
+is also CVE-2026-12617. There are two scenarios:
+
+- A client send queries for a DNAME and A record to the resolver (ns3),
+ and the authoritative server (ans2) responds positively to the A query
+ but delay the DNAME response and respond later negatively;
+
+- A client send queries for a CNAME and A record to the resolver (ns3),
+ and the authoritative server (ans2) responds positively to the A query
+ but delay the CNAME response and respond later with a self-referential
+ CNAME.
+
+The test does not check the results of the queries, however, it expects
+the resolver to correctly handle those and do not assert.
+
+(cherry picked from commit e88271f2e584010157b068cc998dd76451273562)
+
+Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/bb92832fb6ae899bee7206c2d8966258461c2f71
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-12617
+Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-12617
+
+CVE: CVE-2026-12617
+Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/bb92832fb6ae899bee7206c2d8966258461c2f71]
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ bin/tests/system/cname_dname_negcache/ans2/ans.py | 98 ++++++++++++++++++++++
+ .../system/cname_dname_negcache/ns1/bar.test.db | 5 ++
+ .../system/cname_dname_negcache/ns1/named.conf.j2 | 24 ++++++
+ bin/tests/system/cname_dname_negcache/ns1/root.db | 6 ++
+ bin/tests/system/cname_dname_negcache/ns1/test.db | 8 ++
+ .../system/cname_dname_negcache/ns3/named.conf.j2 | 11 +++
+ .../tests_cname_dname_negcache.py | 53 ++++++++++++
+ 7 files changed, 205 insertions(+)
+ create mode 100644 bin/tests/system/cname_dname_negcache/ans2/ans.py
+ create mode 100644 bin/tests/system/cname_dname_negcache/ns1/bar.test.db
+ create mode 100644 bin/tests/system/cname_dname_negcache/ns1/named.conf.j2
+ create mode 100644 bin/tests/system/cname_dname_negcache/ns1/root.db
+ create mode 100644 bin/tests/system/cname_dname_negcache/ns1/test.db
+ create mode 100644 bin/tests/system/cname_dname_negcache/ns3/named.conf.j2
+ create mode 100644 bin/tests/system/cname_dname_negcache/tests_cname_dname_negcache.py
+
+diff --git a/bin/tests/system/cname_dname_negcache/ans2/ans.py b/bin/tests/system/cname_dname_negcache/ans2/ans.py
+new file mode 100644
+index 0000000..eec5c90
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/ans2/ans.py
+@@ -0,0 +1,98 @@
++"""
++Copyright (C) Internet Systems Consortium, Inc. ("ISC")
++
++SPDX-License-Identifier: MPL-2.0
++
++This Source Code Form is subject to the terms of the Mozilla Public
++License, v. 2.0. If a copy of the MPL was not distributed with this
++file, you can obtain one at https://mozilla.org/MPL/2.0/.
++
++See the COPYRIGHT file distributed with this work for additional
++information regarding copyright ownership.
++"""
++
++from collections.abc import AsyncGenerator
++
++from dns import name, rcode, rdataclass, rdatatype, rrset
++
++from isctest.asyncserver import (
++ AsyncDnsServer,
++ DnsResponseSend,
++ QnameQtypeHandler,
++ QueryContext,
++ StaticResponseHandler,
++)
++
++
++def build_rrset(
++ qname: name.Name | str,
++ rtype: rdatatype.RdataType,
++ rdata: str,
++ ttl: int = 300,
++) -> rrset.RRset:
++ return rrset.from_text(qname, ttl, rdataclass.IN, rtype, rdata)
++
++
++class FooTestNsHandler(QnameQtypeHandler, StaticResponseHandler):
++ qnames = ["foo.test."]
++ qtypes = [rdatatype.NS]
++ answer = [build_rrset("foo.test.", rdatatype.NS, "ns.foo.test.")]
++ additional = [build_rrset("ns.foo.test.", rdatatype.A, "10.53.0.2")]
++
++
++class DelayedDnameNegHandler(QnameQtypeHandler, StaticResponseHandler):
++ qnames = ["foo.test."]
++ qtypes = [rdatatype.DNAME]
++ authority = [
++ build_rrset(
++ "foo.test.",
++ rdatatype.SOA,
++ "ns.test. op.ns.test. 2081509183 86400 3600 3600000 300",
++ )
++ ]
++ delay = 1
++
++
++class DnamePosHandler(QnameQtypeHandler, StaticResponseHandler):
++ qnames = ["a.foo.test."]
++ qtypes = [rdatatype.A]
++ answer = [
++ build_rrset("foo.test.", rdatatype.DNAME, "bar.test."),
++ build_rrset("a.foo.test.", rdatatype.CNAME, "a.bar.test."),
++ ]
++
++
++class CnameHandler(QnameQtypeHandler):
++ qnames = ["cname.foo.test."]
++ qtypes = [rdatatype.CNAME, rdatatype.A]
++ answer = [build_rrset("cname.foo.test.", rdatatype.CNAME, "cname.foo.test.")]
++ authority = [
++ build_rrset(
++ "cname.foo.test.",
++ rdatatype.SOA,
++ "ns.test. op.ns.test. 2081509183 86400 3600 3600000 300",
++ )
++ ]
++
++ async def get_responses(
++ self, qctx: QueryContext
++ ) -> AsyncGenerator[DnsResponseSend, None]:
++ qctx.prepare_new_response(with_zone_data=False)
++ if qctx.qtype == rdatatype.CNAME:
++ qctx.response.authority.extend(self.authority)
++ yield DnsResponseSend(qctx.response, authoritative=True, delay=1)
++ else:
++ qctx.response.answer.extend(self.answer)
++ yield DnsResponseSend(qctx.response, authoritative=True)
++
++
++def main() -> None:
++ server = AsyncDnsServer(default_aa=True, default_rcode=rcode.NOERROR)
++ server.install_response_handlers(
++ FooTestNsHandler(), DelayedDnameNegHandler(), DnamePosHandler(), CnameHandler()
++ )
++ server.run()
++
++
++if __name__ == "__main__":
++ main()
+diff --git a/bin/tests/system/cname_dname_negcache/ns1/bar.test.db b/bin/tests/system/cname_dname_negcache/ns1/bar.test.db
+new file mode 100644
+index 0000000..840b9c3
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/ns1/bar.test.db
+@@ -0,0 +1,5 @@
++$TTL 300
++bar.test. IN SOA ns.bar.test. hostmaster.bar.test. 1 600 600 1200 600
++bar.test. NS ns.bar.test.
++ns A 10.53.0.1
++a A 10.0.0.1
+diff --git a/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2 b/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2
+new file mode 100644
+index 0000000..d72dd11
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/ns1/named.conf.j2
+@@ -0,0 +1,24 @@
++options {
++ query-source address @ns.ip@;
++ port @PORT@;
++ pid-file "named.pid";
++ listen-on { @ns.ip@; };
++ listen-on-v6 { none; };
++ recursion no;
++ dnssec-validation no;
++};
++
++zone "." {
++ type primary;
++ file "root.db";
++};
++
++zone "test." {
++ type primary;
++ file "test.db";
++};
++
++zone "bar.test." {
++ type primary;
++ file "bar.test.db";
++};
+diff --git a/bin/tests/system/cname_dname_negcache/ns1/root.db b/bin/tests/system/cname_dname_negcache/ns1/root.db
+new file mode 100644
+index 0000000..c456c45
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/ns1/root.db
+@@ -0,0 +1,6 @@
++$TTL 300
++. IN SOA ns. hostmaster. 1 600 600 1200 600
++. NS a.root-servers.nil.
++a.root-servers.nil. A 10.53.0.1
++test NS ns.test
++ns.test A 10.53.0.1
+diff --git a/bin/tests/system/cname_dname_negcache/ns1/test.db b/bin/tests/system/cname_dname_negcache/ns1/test.db
+new file mode 100644
+index 0000000..acb68e0
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/ns1/test.db
+@@ -0,0 +1,8 @@
++$TTL 300
++test. IN SOA ns.test. hostmaster.test. 1 600 600 1200 600
++test. NS ns.test.
++ns A 10.53.0.1
++bar NS ns.bar
++ns.bar A 10.53.0.1
++foo NS ns.foo
++ns.foo A 10.53.0.2
+diff --git a/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2 b/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2
+new file mode 100644
+index 0000000..197d727
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/ns3/named.conf.j2
+@@ -0,0 +1,11 @@
++options {
++ query-source address @ns.ip@;
++ port @PORT@;
++ pid-file "named.pid";
++ listen-on { @ns.ip@; };
++ listen-on-v6 { none; };
++ recursion yes;
++ dnssec-validation no;
++};
++
++{% include "_common/root.hint.conf" %}
+diff --git a/bin/tests/system/cname_dname_negcache/tests_cname_dname_negcache.py b/bin/tests/system/cname_dname_negcache/tests_cname_dname_negcache.py
+new file mode 100644
+index 0000000..5d21c5b
+--- /dev/null
++++ b/bin/tests/system/cname_dname_negcache/tests_cname_dname_negcache.py
+@@ -0,0 +1,53 @@
++# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
++#
++# SPDX-License-Identifier: MPL-2.0
++#
++# This Source Code Form is subject to the terms of the Mozilla Public
++# License, v. 2.0. If a copy of the MPL was not distributed with this
++# file, you can obtain one at https://mozilla.org/MPL/2.0/.
++#
++# See the COPYRIGHT file distributed with this work for additional
++# information regarding copyright ownership.
++
++from os import environ
++from re import compile as Re
++from socket import AF_INET, SOCK_DGRAM, socket
++
++import isctest
++
++
++def run_attack(ns, name1, type1, name2, type2):
++ msg1 = isctest.query.create(name1, type1, cd=True)
++ msg2 = isctest.query.create(name2, type2, cd=True)
++ port = int(environ["PORT"])
++
++ with socket(AF_INET, SOCK_DGRAM) as sock:
++ # The order the request does out doesn't matter. What is important is
++ # the first query starts recursion before the second query returns the
++ # answer, and the second query returns the answer before the first
++ # query returns the answer. (So, when the NOERROR/NODATA cames back
++ # from the first query, the cache is queried and we get the positive
++ # response cached from the second query attached to the fresp rdataset
++ # of the response of the first query.)
++ # Therefore, the logic is really baked into ans2, which has a 3 seconds
++ # delay to answer the first query.
++ sock.sendto(msg1.to_wire(), (ns.ip, port))
++ sock.sendto(msg2.to_wire(), (ns.ip, port))
++
++ # The second query come back immediately, the resolver caches the DNAME.
++ # The first query come back after 3s (because of intentional ans2 latency
++ # on foo.test./DNAME answer) and should not crash the server.
++ with ns.watch_log_from_start(timeout=15) as watcher:
++ watcher.wait_for_sequence(
++ [
++ Re(r"foo\.test\..*IN\s+SOA\s+ns\.test\.\s+op\.ns\.test\."),
++ ]
++ )
++
++
++def test_dname_negcache(ns3):
++ run_attack(ns3, "foo.test.", "DNAME", "a.foo.test.", "A")
++
++
++def test_cname_negcache(ns3):
++ run_attack(ns3, "cname.foo.test.", "CNAME", "cname.foo.test.", "A")
@@ -33,6 +33,8 @@ SRC_URI = "https://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.xz \
file://CVE-2026-11721-01.patch \
file://CVE-2026-11721-02.patch \
file://CVE-2026-11721-03.patch \
+ file://CVE-2026-12617-01.patch \
+ file://CVE-2026-12617-02.patch \
"
SRC_URI[sha256sum] = "c43ce4548ebed788cd9df63658a7de105ceafba43fcd63fa352b1093e525cd24"
Pick patch from [1] & [2] also mentioned at Debian report in [2] [1] https://gitlab.isc.org/isc-projects/bind9/-/commit/c740c37689f234e21a9b0ef760471ef2cf1133f5 [2] https://gitlab.isc.org/isc-projects/bind9/-/commit/bb92832fb6ae899bee7206c2d8966258461c2f71 [3] https://security-tracker.debian.org/tracker/CVE-2026-12617 Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> --- .../bind/bind/CVE-2026-12617-01.patch | 283 +++++++++++++++++ .../bind/bind/CVE-2026-12617-02.patch | 292 ++++++++++++++++++ .../recipes-connectivity/bind/bind_9.18.49.bb | 2 + 3 files changed, 577 insertions(+) create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-12617-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-12617-02.patch