public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/bind] f45: Key Record using PRIVATEDNS algorithm may lead to exit (CVE-2026-10822)
@ 2026-08-26 8:34
0 siblings, 0 replies; only message in thread
From: @ 2026-08-26 8:34 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/bind
Branch : f45
Commit : c72c35866e76095ca27413a6473f31d1fb8fd4c1
Author : Petr Menšík <pemensik@redhat.com>
Date : 2026-08-25T12:39:56+02:00
Stats : +377/-0 in 3 file(s)
URL : https://src.fedoraproject.org/rpms/bind/c/c72c35866e76095ca27413a6473f31d1fb8fd4c1?branch=f45
Log:
Key Record using PRIVATEDNS algorithm may lead to exit (CVE-2026-10822)
[9.18] [CVE-2026-10822] sec: usr: Fix dns_name_fromwire to record boundaries
Previously, `dns_name_fromwire()` did not honor the record boundary when reading names from the wire, allowing malformed records to be accepted when they should not have been. This has been fixed.
Closes: https://gitlab.isc.org/isc-projects/bind9/-/issues/6004
---
diff --git a/bind-9.18-CVE-2026-10822-test.patch b/bind-9.18-CVE-2026-10822-test.patch
new file mode 100644
index 0000000..f95514f
--- /dev/null
+++ b/bind-9.18-CVE-2026-10822-test.patch
@@ -0,0 +1,320 @@
+From a4ce4c0ce5b8d7630417730dc1b98bf554e0801f Mon Sep 17 00:00:00 2001
+From: Mark Andrews <marka@isc.org>
+Date: Tue, 19 May 2026 10:44:04 +1000
+Subject: [PATCH] Check that dns_name_fromwire honours the active region
+
+When reading DNS records from the wire the active region of the
+source buffer is set to the end of the current record. dns_name_fromwire
+should fail if it attempts to read past this setting.
+
+(cherry picked from commit 3ed821d68b15fe4e6288e3054397d6bce7e65968)
+(cherry picked from commit d413c9ac2e29a728531354a69c8c8234c01b7d1e)
+
+Check that a short PRIVATEDNS record is rejected
+
+A bug in dns_name_fromwire meant that short PRIVATEDNS key
+records where being accepted. Test that this is no longer
+the case.
+
+(cherry picked from commit f48d48027384d8c2210b5ce9e3eac7af101ead3d)
+(cherry picked from commit 19ac8b8e46aeb0a15e217bc7bdf485b31b87d9b4)
+
+POC for PRIVATEDNS DNSKEY overrun not being detected
+
+Construct a DNS message where a PRIVATEDNS DNSKEY identifier
+overruns the record boundary by 3 byte so that the label ends
+at the end of the compression pointer for the next record. The
+next type is less than 256 so the next octet is 00 terminating
+the identifier name. The transfered zone is then written to
+disk using master-format text triggering the assertion when the
+truncated identier is discovered.
+
+Note this test will produce a false result in versions of
+BIND that do not check the PRIVATEDNS identifier as it looks
+for the error message when the transfer is aborted.
+
+(cherry picked from commit 9ce3bce8bc8b4e9c6a9b1e84b5849c33eb27830e)
+(cherry picked from commit 8e066d3fc369e3346f22bb5cfb67a7ab08a74034)
+---
+ bin/tests/system/xfer/ans9/ans.py | 142 ++++++++++++++++++++++++
+ bin/tests/system/xfer/ns6/named.conf.in | 9 ++
+ bin/tests/system/xfer/tests.sh | 16 +++
+ tests/dns/name_test.c | 30 +++++
+ tests/dns/rdata_test.c | 21 ++++
+ 5 files changed, 218 insertions(+)
+ create mode 100644 bin/tests/system/xfer/ans9/ans.py
+
+diff --git a/bin/tests/system/xfer/ans9/ans.py b/bin/tests/system/xfer/ans9/ans.py
+new file mode 100644
+index 0000000000..a9e73953ee
+--- /dev/null
++++ b/bin/tests/system/xfer/ans9/ans.py
+@@ -0,0 +1,142 @@
++"""
++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
++
++import dns.name
++import dns.rcode
++import dns.rdatatype
++import dns.rrset
++
++from isctest.asyncserver import (
++ ControllableAsyncDnsServer,
++ DnsResponseSend,
++ DomainHandler,
++ QueryContext,
++ ResponseAction,
++ ToggleResponsesCommand,
++)
++
++
++class AXFRServer(DomainHandler):
++ """
++ Yield SOA and AXFR responses. Every new AXFR response increments the SOA
++ version.
++ """
++
++ domains = ["xfr-and-reconfig", "private-dns-overrun"]
++
++ def __init__(self) -> None:
++ super().__init__()
++ self.soa_version = 0
++
++ async def get_responses(
++ self, qctx: QueryContext
++ ) -> AsyncGenerator[ResponseAction, None]:
++ # This is oversimplified because I am lazy - we are appending the SOA
++ # RRset to the ANSWER section for _every_ QTYPE. named is only
++ # expected to send a SOA query over UDP and then an AXFR query over
++ # TCP. Responses to both of those start with a SOA RRset in the ANSWER
++ # section :-)
++ soa_message = qctx.response
++ soa_rrset = dns.rrset.from_text(
++ qctx.qname,
++ 300,
++ qctx.qclass,
++ dns.rdatatype.SOA,
++ f". . {self.soa_version} 0 0 0 0",
++ )
++ soa_message.answer.append(soa_rrset)
++
++ yield DnsResponseSend(soa_message)
++
++ if qctx.qtype == dns.rdatatype.SOA:
++ # If QTYPE=SOA, the SOA record is the complete response.
++ return
++
++ if qctx.qtype != dns.rdatatype.AXFR:
++ # If QTYPE=AXFR, we will continue cramming RRsets into the ANSWER
++ # section of a subsequent DNS message below.
++ #
++ # If QTYPE was not SOA or AXFR, abort. Yeah, we just sent a broken
++ # response by yielding DnsResponseSend() with a SOA RRset in the
++ # ANSWER section above. We will have to carry that burden for the
++ # rest of our lives.
++ return
++
++ # Send just the obligatory NS RRset at zone apex in the next message.
++ # This is stupidly inefficient, but makes looping below simpler as we
++ # will already have been done with the mandatory stuff by then.
++ ns_message = qctx.prepare_new_response()
++ ns_rrset = dns.rrset.from_text(
++ qctx.qname, 300, qctx.qclass, dns.rdatatype.NS, "."
++ )
++ ns_message.answer.append(ns_rrset)
++
++ yield DnsResponseSend(ns_message)
++
++ # Generate the AXFR with a txt rrset.
++ txt_message = qctx.prepare_new_response()
++ txt_rrset = dns.rrset.from_text(
++ qctx.qname,
++ 300,
++ qctx.qclass,
++ dns.rdatatype.TXT,
++ "foo bar",
++ )
++ txt_message.answer.append(txt_rrset)
++
++ yield DnsResponseSend(txt_message)
++
++ if qctx.qname == dns.name.from_text("private-dns-overrun"):
++ # A message where the malformed DNSKEY algorithm identifier
++ # finishes on a 00 byte in the next record. Assumes the
++ # next record starts with a compression pointer which is
++ # followed by the type which starts with 00.
++
++ # Generate malformed PRIVATE DNS DNSKEY
++ dnskey_message = qctx.prepare_new_response()
++ dnskey_rrset = dns.rrset.from_text(
++ qctx.qname,
++ 300,
++ qctx.qclass,
++ dns.rdatatype.DNSKEY,
++ "\\# 12 00 00 00 fd 09 00 00 00 00 00 00 00",
++ )
++ dnskey_message.answer.append(dnskey_rrset)
++ # Generate well formed PRIVATE DNS DNSKEY
++ dnskey_rrset = dns.rrset.from_text(
++ qctx.qname,
++ 300,
++ qctx.qclass,
++ dns.rdatatype.DNSKEY,
++ "\\# 12 00 00 00 fd 06 00 00 00 00 00 00 00",
++ )
++ dnskey_message.answer.append(dnskey_rrset)
++
++ yield DnsResponseSend(dnskey_message)
++
++ # Finish the AXFR transaction by sending the second SOA RRset.
++ yield DnsResponseSend(soa_message)
++
++ # This makes sure that the next SOA request causes a new zone transfer
++ self.soa_version += 1
++
++
++if __name__ == "__main__":
++ server = ControllableAsyncDnsServer(
++ default_aa=True, default_rcode=dns.rcode.NOERROR
++ )
++ server.install_control_command(ToggleResponsesCommand())
++ server.install_response_handler(AXFRServer())
++ server.run()
+diff --git a/bin/tests/system/xfer/ns6/named.conf.in b/bin/tests/system/xfer/ns6/named.conf.in
+index 142383c89a..63809448f0 100644
+--- a/bin/tests/system/xfer/ns6/named.conf.in
++++ b/bin/tests/system/xfer/ns6/named.conf.in
+@@ -83,3 +83,12 @@ zone "ixfr-too-big" {
+ primaries { 10.53.0.1; };
+ file "ixfr-too-big.bk";
+ };
++
++# GL#6004
++zone "private-dns-overrun" {
++ type secondary;
++ primaries { 10.53.0.9; };
++ file "private-dns-overrun.bk";
++ masterfile-format text; # force bug to be exercised
++ request-ixfr no; # ans9 supports only axfr
++};
+diff --git a/bin/tests/system/xfer/tests.sh b/bin/tests/system/xfer/tests.sh
+index a2c0adbc28..e08be175b7 100755
+--- a/bin/tests/system/xfer/tests.sh
++++ b/bin/tests/system/xfer/tests.sh
+@@ -622,5 +622,21 @@ if [ $tmp -eq 0 ]; then
+ fi
+ status=$((status + tmp))
+
++# def test_malformed_private_dns_identifier_overrun(ns6):
++# isctest.log.info(
++# "Check that a malformed PRIVATEDNS DNSKEY which overruns the record is rejected"
++# )
++# with ns6.watch_log_from_start(timeout=60) as watcher_transfer_completed:
++# watcher_transfer_completed.wait_for_line(
++# "zone private-dns-overrun/IN: zone transfer finished: unexpected end of input"
++# )
++n=$((n + 1))
++echo_i "Check that a malformed PRIVATEDNS DNSKEY which overruns the record is rejected ($n)"
++tmp=0
++nextpartreset ns6/named.run
++retry 60 wait_for_message "zone private-dns-overrun/IN: zone transfer finished: unexpected end of input" || tmp=1
++if test $tmp != 0; then echo_i "failed"; fi
++status=$((status + tmp))
++
+ echo_i "exit status: $status"
+ [ $status -eq 0 ] || exit 1
+diff --git a/tests/dns/name_test.c b/tests/dns/name_test.c
+index fb34dcace1..95f6598eb8 100644
+--- a/tests/dns/name_test.c
++++ b/tests/dns/name_test.c
+@@ -335,6 +335,35 @@ ISC_RUN_TEST_IMPL(fromregion) {
+ assert_false(dns_name_isabsolute(&name));
+ }
+
++ISC_RUN_TEST_IMPL(fromwire) {
++ dns_decompress_t dctx;
++ dns_fixedname_t fixed;
++ dns_name_t *name = dns_fixedname_initname(&fixed);
++ isc_buffer_t b;
++ unsigned char source[] = { 0x03, 'o', 'n', 'e', 0x00, 0x03,
++ 't', 'w', 'o', 0x00, 0x05, 't',
++ 'h', 'r', 'e', 'e', 0x00 };
++ isc_result_t result;
++
++ isc_buffer_init(&b, source, sizeof(source));
++ isc_buffer_add(&b, sizeof(source));
++ isc_buffer_setactive(&b, 10); /* names 'one.' and 'two.' */
++
++ /*
++ * We should only be able to read two names from the buffer
++ * as the active region has been set to cover only the first
++ * two.
++ */
++ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_STRICT);
++ dns_decompress_setmethods(&dctx, DNS_COMPRESS_NONE);
++ result = dns_name_fromwire(name, &b, &dctx, 0, NULL);
++ assert_int_equal(result, ISC_R_SUCCESS);
++ result = dns_name_fromwire(name, &b, &dctx, 0, NULL);
++ assert_int_equal(result, ISC_R_SUCCESS);
++ result = dns_name_fromwire(name, &b, &dctx, 0, NULL);
++ assert_int_not_equal(result, ISC_R_SUCCESS);
++}
++
+ /* is trust-anchor-telemetry test */
+ ISC_RUN_TEST_IMPL(istat) {
+ dns_fixedname_t fixed;
+@@ -778,6 +807,7 @@ ISC_TEST_LIST_START
+ ISC_TEST_ENTRY(fullcompare)
+ ISC_TEST_ENTRY(compression)
+ ISC_TEST_ENTRY(fromregion)
++ISC_TEST_ENTRY(fromwire)
+ ISC_TEST_ENTRY(istat)
+ ISC_TEST_ENTRY(init)
+ ISC_TEST_ENTRY(invalidate)
+diff --git a/tests/dns/rdata_test.c b/tests/dns/rdata_test.c
+index 6354819d10..7f0df6e046 100644
+--- a/tests/dns/rdata_test.c
++++ b/tests/dns/rdata_test.c
+@@ -2199,6 +2199,27 @@ ISC_RUN_TEST_IMPL(key) {
+
+ check_rdata(NULL, wire_ok, NULL, false, dns_rdataclass_in,
+ dns_rdatatype_key, sizeof(dns_rdata_key_t));
++
++ /*
++ * A valid PRIVATEDNS record with an active region shorter than the
++ * actual record length. A bug in dns_name_fromwire meant that this
++ * was previously accepted.
++ */
++ dns_decompress_t dctx;
++ unsigned char key[] = { 0x00, 0x00, 0x00, 253, 0x07, 'e', 'x',
++ 'a', 'm', 'p', 'l', 'e', 0x00 };
++ unsigned char buf[sizeof(key)];
++ isc_buffer_t source, target;
++ isc_result_t result;
++
++ isc_buffer_init(&source, key, sizeof(key));
++ isc_buffer_add(&source, sizeof(key));
++ isc_buffer_setactive(&source, sizeof(key) - 1);
++ isc_buffer_init(&target, buf, sizeof(buf));
++ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
++ result = dns_rdata_fromwire(NULL, dns_rdataclass_in, dns_rdatatype_key,
++ &source, &dctx, 0, &target);
++ assert_int_not_equal(result, ISC_R_SUCCESS);
+ }
+
+ /*
+--
+2.55.0
+
diff --git a/bind-9.18-CVE-2026-10822.patch b/bind-9.18-CVE-2026-10822.patch
new file mode 100644
index 0000000..22cdbdd
--- /dev/null
+++ b/bind-9.18-CVE-2026-10822.patch
@@ -0,0 +1,54 @@
+From 7596cbc240b0492461943f7c34d040fb66a7554c Mon Sep 17 00:00:00 2001
+From: Mark Andrews <marka@isc.org>
+Date: Tue, 19 May 2026 15:00:17 +1000
+Subject: [PATCH] Fix the yaml query zone name code in dnstap-read
+
+When the buffer to read the query zone name was constructed
+isc_buffer_setactive was not called. This is now needed as
+dns_name_fromwire is being corrected to check the active region.
+
+(cherry picked from commit a25522c28c46655a81d2bf1d96374c81d834b157)
+(cherry picked from commit a5f1a9d0d2ec021618924b14202ac96ead8299c1)
+
+Fix dns_name_fromwire to honour the active region
+
+dns_name_fromwire was not honouring the source buffer's active
+region when reading names from the wire. This allowed malformed
+records to be accepted when they shouldn't have been. This has
+been corrected.
+
+(cherry picked from commit 7c4f07a7ef6b571073327b02209df7f75b9363ff)
+(cherry picked from commit e73b70a64453e7d97a11cb5f0afe8bb02d34aaf8)
+---
+ bin/tools/dnstap-read.c | 1 +
+ lib/dns/name.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/bin/tools/dnstap-read.c b/bin/tools/dnstap-read.c
+index a1d0243a1a..bb78ae12b1 100644
+--- a/bin/tools/dnstap-read.c
++++ b/bin/tools/dnstap-read.c
+@@ -298,6 +298,7 @@ print_yaml(dns_dtdata_t *dt) {
+
+ isc_buffer_init(&b, m->query_zone.data, m->query_zone.len);
+ isc_buffer_add(&b, m->query_zone.len);
++ isc_buffer_setactive(&b, m->query_zone.len);
+
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
+ result = dns_name_fromwire(name, &b, &dctx, 0, NULL);
+diff --git a/lib/dns/name.c b/lib/dns/name.c
+index cc0e30e5b5..2ce868a2ba 100644
+--- a/lib/dns/name.c
++++ b/lib/dns/name.c
+@@ -1833,7 +1833,7 @@ dns_name_fromwire(dns_name_t *const name, isc_buffer_t *const source,
+ * The amount of the source we consumed is set once.
+ */
+ const uint8_t *const source_buf = isc_buffer_base(source);
+- const uint8_t *const source_max = isc_buffer_used(source);
++ const uint8_t *const source_max = isc_buffer_active(source);
+ const uint8_t *const start = isc_buffer_current(source);
+ const uint8_t *marker = start;
+ const uint8_t *cursor = start;
+--
+2.55.0
+
diff --git a/bind.spec b/bind.spec
index bbe677d..c8f2ddf 100644
--- a/bind.spec
+++ b/bind.spec
@@ -164,6 +164,9 @@ Patch35: 0001-Use-variable-PROGRAM_SUFFIX-in-install-target.patch
# https://gitlab.isc.org/isc-projects/bind9/-/work_items/5856
Patch36: bind-9.18-CVE-2026-11331.patch
Patch37: bind-9.18-CVE-2026-11331-test.patch
+# https://gitlab.isc.org/isc-projects/bind9/commit/c5d2fc706ca3635d9928c1cc68db73bffb35d772
+Patch38: bind-9.18-CVE-2026-10822.patch
+Patch40: bind-9.18-CVE-2026-10822-test.patch
%{?systemd_ordering}
# https://fedoraproject.org/wiki/Changes/RPMSuportForSystemdSysusers
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-26 8:34 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-26 8:34 [rpms/bind] f45: Key Record using PRIVATEDNS algorithm may lead to exit (CVE-2026-10822)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox