From patchwork Mon Sep 28 07:11:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 99448 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1703DC9833E for ; Mon, 28 Sep 2026 07:12:31 +0000 (UTC) Received: from mail-dy2-f42.google.com (mail-dy2-f42.google.com [74.125.229.42]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.52910.1790579544982218338 for ; Mon, 28 Sep 2026 00:12:25 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=KAXNghDz; spf=pass (domain: mvista.com, ip: 74.125.229.42, mailfrom: hprajapati@mvista.com) Received: by mail-dy2-f42.google.com with SMTP id 5a478bee46e88-3428f70d7e7so1414051eec.3 for ; Mon, 28 Sep 2026 00:12:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1790579544; x=1791184344; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=7vsazFKn6PzajvAwVGf8vwswBv0MBu2POAMxyF/ifa8=; b=KAXNghDzj+uGR9dk3xOZY0Ek40O5asAMWal+ILqmzDgjtBT7V1fF9KqSv+y26gH/X2 2iZiYAGMZHFrv4arPyGHkwL3FkILwqjG8OMsq0Laj1JEfAZjHqyeSNRrkPA+VySBdVEH CWEPiiIWsfplQq1iR/z/FJ5iLcpcwm43M/rrQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790579544; x=1791184344; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=7vsazFKn6PzajvAwVGf8vwswBv0MBu2POAMxyF/ifa8=; b=XRK0BRQ0b87AAmtKObdus6h6AzrXJRVg3EYsikCLUM/grp5r8t/82NlwmFNl4x+a25 ioWxwGwURmI2Pcepc7DhaDoGzRgVsogHeoHnBbHAa+3GrqXWSgRY5vnyr0C76yqRgHY/ Juu6JntJVDoanknX7G4EHizxyavRav4cKjxRX1h4CxLW/CIQIkEHP47aLoFNpq/qY+pD LAh26PeOZtU69byGbTuYs/wbZbnNvX2MzAayG2OjZkdixfDPyCLzZhx7U7zK80uUra1h cDb9XuuvPKX9+MBo7NgQ/UuwwNdtYgQyYdYkAsoEp4sVzMBSodq8xuqcip5DgsKGlxoP FAbg== X-Gm-Message-State: AFq9FYI4PGNC2nKfmvhDJ+Kh6F8yfjatAVMwvbvs5GxbUf/jWJ0uFdlZ qZY4JQ9UYCIKkbzWPLhvxvRTkM94xnk9qMWhEYlBhW2CYiTJz/AEsR/+Vc4kTGm005GtSkdoTPc Vl801oog= X-Gm-Gg: AYBFou1zTkT54aDmrURlzFgmwJtux367zACp2QlOyewGtd0g9PEPCASu4W7t1aUz6Vr R52czFodTH4YIcXJIIc24f6uT6/MfUg8OQMzJn0aCgoIl0UljVNf1c/pbmhhC1cNytRlzoU6jro KReVL9K5lI6oGru54uGgJ+hg+SEUIxJXdkLN9zTz3JsvIdEnC9OcIv0vp0CMRDHNagHZ0HSxPsx mucI7uciL+RwmV5XegFOPq8x5uLiMNi2jiDKTXwgZrUTR0pvjKuUOlUnE4r1JSkLDdsHOB+yzg7 128C7PRwfGNfC4h8s8T3oWs9IL4Xsq9C+JWpKfxxy7ZHF4mlYAt6caEwOivTvUpDxK1BJa0SyGD Y3P0zdILLflUVJD23908RsXELnM1lxzGyU60mpJ5eu5bPRf8PTXDDTCGjN4jZYTw2C3u0G97dpm Ru97G4vmnEJaMNAzJinPWmk46cfnlebVKk0T/Q+bS4dKZ9aQXptVdrd5CV+55bi68qwDy3P4tvu qxFCFDKLiI7 X-Received: by 2002:a05:7301:fd8a:b0:33b:dd20:f79c with SMTP id 5a478bee46e88-34270ab8840mr8916435eec.12.1790579543573; Mon, 28 Sep 2026 00:12:23 -0700 (PDT) Received: from MVIN00013.mvista.com ([150.129.170.212]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3434958c3adsm31166948eec.22.2026.09.28.00.12.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2026 00:12:22 -0700 (PDT) From: Hitendra Prajapati To: openembedded-core@lists.openembedded.org Cc: Hitendra Prajapati Subject: [scarthgap][PATCH 1/6] bind: fix for CVE-2026-10723 Date: Mon, 28 Sep 2026 12:41:06 +0530 Message-ID: <20260928071115.304055-1-hprajapati@mvista.com> X-Mailer: git-send-email 2.50.1 MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 07:12:31 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/246731 Pick patch from [1], [2] & [3] also mentioned at Debian report in [4] [1] https://gitlab.isc.org/isc-projects/bind9/-/commit/c9cb6a5e24e43489cf3fd4d4cc2193b6a74499cb [2] https://gitlab.isc.org/isc-projects/bind9/-/commit/35e3d49d2222c13786a06021c7ed583d2a656e51 [3] https://gitlab.isc.org/isc-projects/bind9/-/commit/833dd3b230b92596074e8da15b12298f46c939f2 [4] https://security-tracker.debian.org/tracker/CVE-2026-10723 Signed-off-by: Hitendra Prajapati --- .../bind/bind/CVE-2026-10723-01.patch | 70 +++ .../bind/bind/CVE-2026-10723-02.patch | 496 ++++++++++++++++++ .../bind/bind/CVE-2026-10723-03.patch | 310 +++++++++++ .../recipes-connectivity/bind/bind_9.18.49.bb | 3 + 4 files changed, 879 insertions(+) create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10723-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10723-02.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10723-03.patch diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-10723-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10723-01.patch new file mode 100644 index 0000000000..ffec38aea2 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10723-01.patch @@ -0,0 +1,70 @@ +From: Evan Hunt +Date: Thu, 21 May 2026 14:41:55 -0700 +Subject: Check NSEC3 signer matches the owning zone + +When validating NSEC3 records, reject any signature whose signer field +does not match the zone owning the NSEC3. + +This ensures that a child zone cannot impersonate its parent and forge +NXDOMAIN responses for sibling domains. + +Fixes: isc-projects/bind9#5874 +(cherry picked from commit 6e5066bb1f0f12d090e8707adb7d6ccf74f8012b) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/c9cb6a5e24e43489cf3fd4d4cc2193b6a74499cb +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10723 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10723 + +CVE: CVE-2026-10723 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/c9cb6a5e24e43489cf3fd4d4cc2193b6a74499cb] +Signed-off-by: Hitendra Prajapati +--- + lib/dns/dnssec.c | 19 +++++++++++++++++-- + lib/isc/result.c | 2 +- + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c +index c7e9224..1725de3 100644 +--- a/lib/dns/dnssec.c ++++ b/lib/dns/dnssec.c +@@ -404,10 +404,25 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + } + + /* +- * NS, SOA and DNSKEY records are signed by their owner. +- * DS records are signed by the parent. ++ * NS, SOA and DNSKEY records are signed by their owners. ++ * NSEC3 records are signed by the apex, exactly one level up ++ * from their owner names. ++ * DS records are signed by the parent zone. + */ + switch (set->type) { ++ case dns_rdatatype_nsec3: { ++ dns_name_t apex = DNS_NAME_INITEMPTY; ++ labels = dns_name_countlabels(name); ++ if (labels <= 1) { ++ inc_stat(dns_dnssecstats_fail); ++ return DNS_R_INVALIDNSEC3; ++ } ++ dns_name_split(name, labels - 1, NULL, &apex); ++ if (!dns_name_equal(&apex, &sig.signer)) { ++ inc_stat(dns_dnssecstats_fail); ++ return DNS_R_SIGINVALID; ++ } ++ } break; + case dns_rdatatype_ns: + case dns_rdatatype_soa: + case dns_rdatatype_dnskey: +diff --git a/lib/isc/result.c b/lib/isc/result.c +index dbd0431..f78e689 100644 +--- a/lib/isc/result.c ++++ b/lib/isc/result.c +@@ -198,7 +198,7 @@ static const char *description[ISC_R_NRESULTS] = { + [DNS_R_COVERINGNSEC] = "covering NSEC record returned", + [DNS_R_MXISADDRESS] = "MX is an address", + [DNS_R_DUPLICATE] = "duplicate query", +- [DNS_R_INVALIDNSEC3] = "invalid NSEC3 owner name (wildcard)", ++ [DNS_R_INVALIDNSEC3] = "invalid NSEC3 owner name", + [DNS_R_NOTPRIMARY] = "not primary", + [DNS_R_BROKENCHAIN] = "broken trust chain", + [DNS_R_EXPIRED] = "expired", diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-10723-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10723-02.patch new file mode 100644 index 0000000000..a3ff47b8bf --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10723-02.patch @@ -0,0 +1,496 @@ +From: Alessio Podda +Date: Wed, 3 Jun 2026 10:42:43 +0200 +Subject: Reproducer for #5874 NSEC3 impersonation + +LLM generated. + +(cherry picked from commit f3e2eb333be3ac636f745aa13cfb8d9ee8af87d8) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/35e3d49d2222c13786a06021c7ed583d2a656e51 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10723 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10723 + +CVE: CVE-2026-10723 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/35e3d49d2222c13786a06021c7ed583d2a656e51b] +Signed-off-by: Hitendra Prajapati +--- + .../ans1/ans.py} | 8 +- + .../repro_5874_nsec3_parent/ns2/named.conf.j2 | 35 +++ + bin/tests/system/repro_5874_nsec3_parent/server.py | 249 +++++++++++++++++++++ + .../tests_repro_5874_nsec3_parent.py | 144 ++++++++++++ + 4 files changed, 433 insertions(+), 3 deletions(-) + copy bin/tests/system/{glue/setup.sh => repro_5874_nsec3_parent/ans1/ans.py} (83%) + create mode 100644 bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 + create mode 100644 bin/tests/system/repro_5874_nsec3_parent/server.py + create mode 100644 bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py + +diff --git a/bin/tests/system/glue/setup.sh b/bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py +similarity index 83% +copy from bin/tests/system/glue/setup.sh +copy to bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py +index 82240a7..614f26a 100644 +--- a/bin/tests/system/glue/setup.sh ++++ b/bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py +@@ -1,4 +1,4 @@ +-#!/bin/sh ++#!/usr/bin/python3 + + # Copyright (C) Internet Systems Consortium, Inc. ("ISC") + # +@@ -11,6 +11,8 @@ + # See the COPYRIGHT file distributed with this work for additional + # information regarding copyright ownership. + +-. ../conf.sh ++from server import main + +-copy_setports ns1/named.conf.in ns1/named.conf ++ ++if __name__ == "__main__": ++ main() +diff --git a/bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 b/bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 +new file mode 100644 +index 0000000..9358866 +--- /dev/null ++++ b/bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 +@@ -0,0 +1,35 @@ ++// validating resolver ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port @PORT@; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion yes; ++ dnssec-validation yes; ++ trust-anchor-telemetry no; ++ resolver-query-timeout 5000; ++}; ++ ++controls { ++ inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; }; ++}; ++ ++include "../../_common/rndc.key"; ++ ++zone "." { ++ type hint; ++ file "../../_common/root.hint"; ++}; ++ ++zone "tld.test" { ++ type static-stub; ++ server-addresses { 10.53.0.1; }; ++}; ++ ++trust-anchors { ++ tld.test. static-key 257 3 13 "@TLD_DNSKEY@"; ++}; +diff --git a/bin/tests/system/repro_5874_nsec3_parent/server.py b/bin/tests/system/repro_5874_nsec3_parent/server.py +new file mode 100644 +index 0000000..c6856bb +--- /dev/null ++++ b/bin/tests/system/repro_5874_nsec3_parent/server.py +@@ -0,0 +1,249 @@ ++#!/usr/bin/python3 ++ ++# 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 dataclasses import dataclass ++from pathlib import Path ++ ++import json ++ ++from cryptography.hazmat.primitives import serialization ++ ++import dns.dnssec ++import dns.flags ++import dns.message ++import dns.name ++import dns.rdata ++import dns.rdataclass ++import dns.rcode ++import dns.rdatatype ++import dns.rrset ++ ++from isctest.asyncserver import ( ++ AsyncDnsServer, ++ DnsResponseSend, ++ QueryContext, ++ ResponseHandler, ++) ++ ++TTL = 300 ++TLD = "tld.test." ++APEX_HASH = "1B40241KFORIOG780N4IKSCRLVETPCTQ" ++ATTACKER = f"{APEX_HASH.lower()}.{TLD}" ++VICTIM = f"victim.{TLD}" ++AUTH_IP = "10.53.0.1" ++ ++ ++@dataclass(frozen=True) ++class Key: ++ zone: dns.name.Name ++ private_key: object ++ dnskey: dns.rdata.Rdata ++ ds: dns.rdata.Rdata ++ ++ ++def name(text: str) -> dns.name.Name: ++ return dns.name.from_text(text) ++ ++ ++def load_keys() -> dict[str, Key]: ++ path = Path(__file__).resolve().parent / "keys.json" ++ with path.open(encoding="utf-8") as keys_file: ++ raw_keys = json.load(keys_file) ++ ++ keys = {} ++ for zone, raw_key in raw_keys.items(): ++ private_key = serialization.load_pem_private_key( ++ raw_key["private_pem"].encode("ascii"), ++ password=None, ++ ) ++ dnskey = dns.rdata.from_text( ++ dns.rdataclass.IN, dns.rdatatype.DNSKEY, raw_key["dnskey"] ++ ) ++ ds = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.DS, raw_key["ds"]) ++ keys[zone] = Key(name(zone), private_key, dnskey, ds) ++ ++ return keys ++ ++ ++def rrset(owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str) -> dns.rrset.RRset: ++ return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, *rdatas) ++ ++ ++def rrset_from_rdata(owner: str, rdata: dns.rdata.Rdata) -> dns.rrset.RRset: ++ return dns.rrset.from_rdata(name(owner), TTL, rdata) ++ ++ ++def rrsig_rrset(covered: dns.rrset.RRset, signer: Key) -> dns.rrset.RRset: ++ rrsig = dns.dnssec.sign( ++ covered, ++ signer.private_key, ++ signer.zone, ++ signer.dnskey, ++ lifetime=86400, ++ verify=True, ++ ) ++ return dns.rrset.from_rdata(covered.name, covered.ttl, rrsig) ++ ++ ++def add_signed( ++ section: list[dns.rrset.RRset], covered: dns.rrset.RRset, signer: Key ++) -> None: ++ section.append(covered) ++ section.append(rrsig_rrset(covered, signer)) ++ ++ ++def dnskey_rrset(zone: str, zone_key: Key) -> dns.rrset.RRset: ++ return rrset_from_rdata(zone, zone_key.dnskey) ++ ++ ++def ds_rrset(zone: str, zone_key: Key) -> dns.rrset.RRset: ++ return rrset_from_rdata(zone, zone_key.ds) ++ ++ ++def soa_rrset(zone: str) -> dns.rrset.RRset: ++ return rrset( ++ zone, ++ dns.rdatatype.SOA, ++ f"ns.{zone} hostmaster.{zone} 1 3600 600 86400 300", ++ ) ++ ++ ++def ns_rrset(zone: str, ns_target: str) -> dns.rrset.RRset: ++ return rrset(zone, dns.rdatatype.NS, ns_target) ++ ++ ++def glue_rrset(ns_target: str, address: str) -> dns.rrset.RRset: ++ return rrset(ns_target, dns.rdatatype.A, address) ++ ++ ++def answer_dnskey(response: dns.message.Message, zone: str, zone_key: Key) -> None: ++ add_signed(response.answer, dnskey_rrset(zone, zone_key), zone_key) ++ ++ ++def answer_soa(response: dns.message.Message, zone: str, zone_key: Key) -> None: ++ add_signed(response.answer, soa_rrset(zone), zone_key) ++ ++ ++def answer_ns( ++ response: dns.message.Message, zone: str, ns_target: str, zone_key: Key ++) -> None: ++ add_signed(response.answer, ns_rrset(zone, ns_target), zone_key) ++ ++ ++def answer_ds( ++ response: dns.message.Message, zone: str, child_key: Key, parent_key: Key ++) -> None: ++ add_signed(response.answer, ds_rrset(zone, child_key), parent_key) ++ ++ ++def child_nsec3_rrset() -> dns.rrset.RRset: ++ rdata = dns.rdata.from_text( ++ dns.rdataclass.IN, ++ dns.rdatatype.NSEC3, ++ f"1 0 0 - {APEX_HASH} NS SOA RRSIG DNSKEY NSEC3PARAM", ++ ) ++ return dns.rrset.from_rdata(name(f"{APEX_HASH}.{TLD}"), TTL, rdata) ++ ++ ++def forged_nxdomain(response: dns.message.Message, keys: dict[str, Key]) -> None: ++ response.set_rcode(dns.rcode.NXDOMAIN) ++ ++ add_signed(response.authority, soa_rrset(TLD), keys[TLD]) ++ ++ # The owner name derives zone "tld.test.", but the RRSIG signer is the ++ # secure child zone "1b40241kforiog780n4ikscrlvetpctq.tld.test.". ++ add_signed(response.authority, child_nsec3_rrset(), keys[ATTACKER]) ++ ++ ++class SignedResponseHandler(ResponseHandler): ++ def __init__(self, keys: dict[str, Key]) -> None: ++ self.keys = keys ++ ++ async def get_responses( ++ self, qctx: QueryContext ++ ) -> AsyncGenerator[DnsResponseSend, None]: ++ qctx.prepare_new_response(with_zone_data=False) ++ qctx.response.flags |= dns.flags.AA ++ qctx.response.set_rcode(dns.rcode.NOERROR) ++ self.respond(qctx) ++ yield DnsResponseSend(qctx.response, authoritative=True) ++ ++ def respond(self, qctx: QueryContext) -> None: ++ raise NotImplementedError ++ ++ ++class VictimForgedNxdomainHandler(SignedResponseHandler): ++ def match(self, qctx: QueryContext) -> bool: ++ return qctx.qname == name(VICTIM) and qctx.qtype == dns.rdatatype.A ++ ++ def respond(self, qctx: QueryContext) -> None: ++ forged_nxdomain(qctx.response, self.keys) ++ ++ ++class ChildDsHandler(SignedResponseHandler): ++ def match(self, qctx: QueryContext) -> bool: ++ return qctx.qname == name(ATTACKER) and qctx.qtype == dns.rdatatype.DS ++ ++ def respond(self, qctx: QueryContext) -> None: ++ answer_ds(qctx.response, ATTACKER, self.keys[ATTACKER], self.keys[TLD]) ++ ++ ++class AttackerZoneHandler(SignedResponseHandler): ++ def match(self, qctx: QueryContext) -> bool: ++ return qctx.qname.is_subdomain(name(ATTACKER)) ++ ++ def respond(self, qctx: QueryContext) -> None: ++ if qctx.qname == name(ATTACKER): ++ if qctx.qtype == dns.rdatatype.DNSKEY: ++ answer_dnskey(qctx.response, ATTACKER, self.keys[ATTACKER]) ++ elif qctx.qtype == dns.rdatatype.SOA: ++ answer_soa(qctx.response, ATTACKER, self.keys[ATTACKER]) ++ else: ++ answer_ns(qctx.response, ATTACKER, f"ns.{ATTACKER}", self.keys[ATTACKER]) ++ qctx.response.additional.append(glue_rrset(f"ns.{ATTACKER}", AUTH_IP)) ++ return ++ ++ qctx.response.set_rcode(dns.rcode.NXDOMAIN) ++ add_signed(qctx.response.authority, soa_rrset(ATTACKER), self.keys[ATTACKER]) ++ ++ ++class TldZoneHandler(SignedResponseHandler): ++ def match(self, qctx: QueryContext) -> bool: ++ return qctx.qname.is_subdomain(name(TLD)) ++ ++ def respond(self, qctx: QueryContext) -> None: ++ if qctx.qname == name(TLD): ++ if qctx.qtype == dns.rdatatype.DNSKEY: ++ answer_dnskey(qctx.response, TLD, self.keys[TLD]) ++ elif qctx.qtype == dns.rdatatype.SOA: ++ answer_soa(qctx.response, TLD, self.keys[TLD]) ++ else: ++ answer_ns(qctx.response, TLD, "ns.tld.test.", self.keys[TLD]) ++ qctx.response.additional.append(glue_rrset("ns.tld.test.", AUTH_IP)) ++ return ++ ++ qctx.response.set_rcode(dns.rcode.NXDOMAIN) ++ add_signed(qctx.response.authority, soa_rrset(TLD), self.keys[TLD]) ++ ++ ++def main() -> None: ++ keys = load_keys() ++ server = AsyncDnsServer(default_aa=True) ++ server.install_response_handlers( ++ VictimForgedNxdomainHandler(keys), ++ ChildDsHandler(keys), ++ AttackerZoneHandler(keys), ++ TldZoneHandler(keys), ++ ) ++ server.run() +diff --git a/bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py b/bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py +new file mode 100644 +index 0000000..5fbeff5 +--- /dev/null ++++ b/bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py +@@ -0,0 +1,144 @@ ++#!/usr/bin/python3 ++ ++# 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 pathlib import Path ++ ++import json ++ ++from cryptography.hazmat.primitives import serialization ++from cryptography.hazmat.primitives.asymmetric import ec ++ ++import dns.dnssec ++import dns.flags ++import dns.name ++import dns.rdataclass ++import dns.rdatatype ++import pytest ++ ++import isctest ++ ++APEX_HASH = "1B40241KFORIOG780N4IKSCRLVETPCTQ" ++ATTACKER = f"{APEX_HASH.lower()}.tld.test." ++VICTIM = "victim.tld.test." ++AUTH = "10.53.0.1" ++RESOLVER = "10.53.0.2" ++ ++pytestmark = pytest.mark.extra_artifacts( ++ [ ++ "ans*/ans.run", ++ "keys.json", ++ ] ++) ++ ++ ++def _make_key(zone): ++ private_key = ec.generate_private_key(ec.SECP256R1()) ++ dnskey = dns.dnssec.make_dnskey( ++ private_key.public_key(), ++ algorithm="ECDSAP256SHA256", ++ flags=257, ++ ) ++ ds = dns.dnssec.make_ds(dns.name.from_text(zone), dnskey, "SHA256") ++ private_pem = private_key.private_bytes( ++ encoding=serialization.Encoding.PEM, ++ format=serialization.PrivateFormat.PKCS8, ++ encryption_algorithm=serialization.NoEncryption(), ++ ).decode("ascii") ++ return { ++ "private_pem": private_pem, ++ "dnskey": dnskey.to_text(), ++ "ds": ds.to_text(), ++ } ++ ++ ++def bootstrap(): ++ zones = ["tld.test.", ATTACKER] ++ keys = {zone: _make_key(zone) for zone in zones} ++ ++ Path("keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") ++ ++ tld_dnskey = "".join(keys["tld.test."]["dnskey"].split()[3:]) ++ return {"TLD_DNSKEY": tld_dnskey} ++ ++ ++def _check_direct_dnskey_response(zone): ++ query = isctest.query.create(zone, "DNSKEY") ++ response = isctest.query.tcp(query, AUTH) ++ ++ isctest.check.noerror(response) ++ assert response.flags & dns.flags.AA ++ assert ( ++ response.get_rrset( ++ response.answer, ++ dns.name.from_text(zone), ++ dns.rdataclass.IN, ++ dns.rdatatype.DNSKEY, ++ ) ++ is not None ++ ), response ++ ++ ++def _check_direct_ds_response(zone): ++ query = isctest.query.create(zone, "DS") ++ response = isctest.query.tcp(query, AUTH) ++ ++ isctest.check.noerror(response) ++ assert response.flags & dns.flags.AA ++ assert ( ++ response.get_rrset( ++ response.answer, ++ dns.name.from_text(zone), ++ dns.rdataclass.IN, ++ dns.rdatatype.DS, ++ ) ++ is not None ++ ), response ++ ++ ++def test_repro_5874_direct_forged_nsec3_response_has_child_signer(): ++ _check_direct_dnskey_response("tld.test.") ++ _check_direct_dnskey_response(ATTACKER) ++ _check_direct_ds_response(ATTACKER) ++ ++ query = isctest.query.create(VICTIM, "A") ++ response = isctest.query.tcp(query, AUTH) ++ ++ isctest.check.nxdomain(response) ++ assert response.flags & dns.flags.AA ++ ++ nsec3_owner = dns.name.from_text(f"{APEX_HASH}.tld.test.") ++ nsec3 = response.get_rrset( ++ response.authority, ++ nsec3_owner, ++ dns.rdataclass.IN, ++ dns.rdatatype.NSEC3, ++ ) ++ rrsig = response.get_rrset( ++ response.authority, ++ nsec3_owner, ++ dns.rdataclass.IN, ++ dns.rdatatype.RRSIG, ++ covers=dns.rdatatype.NSEC3, ++ ) ++ ++ assert nsec3 is not None, response ++ assert rrsig is not None, response ++ assert rrsig[0].signer == dns.name.from_text(ATTACKER) ++ ++ ++def test_repro_5874_resolver_rejects_child_signed_nsec3_parent_proof(): ++ query = isctest.query.create(VICTIM, "A") ++ response = isctest.query.tcp(query, RESOLVER) ++ ++ isctest.check.servfail(response) ++ isctest.check.noadflag(response) diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-10723-03.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10723-03.patch new file mode 100644 index 0000000000..5461b3c87e --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10723-03.patch @@ -0,0 +1,310 @@ +From: Matthijs Mekking +Date: Thu, 4 Jun 2026 16:12:50 +0200 +Subject: Update reproducer #5874 + +Update the llm generated reproducer: +- Move server.py into ans1/ans.py +- Remove unnecessary named.conf configuration options +- Add comments describing the steps (copied from GL issue) +- Rename system test + +(cherry picked from commit c1321fef165a2ef8c2bff971901c58941e8e694c) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/833dd3b230b92596074e8da15b12298f46c939f2 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10723 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10723 + +CVE: CVE-2026-10723 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/833dd3b230b92596074e8da15b12298f46c939f2] +Signed-off-by: Hitendra Prajapati +--- + .../server.py => nsec3_impersonation/ans1/ans.py} | 81 +++++++++++++++------- + .../ns2/named.conf.j2 | 2 - + .../tests_nsec3_impersonation.py} | 38 ++++++---- + .../system/repro_5874_nsec3_parent/ans1/ans.py | 18 ----- + 4 files changed, 79 insertions(+), 60 deletions(-) + rename bin/tests/system/{repro_5874_nsec3_parent/server.py => nsec3_impersonation/ans1/ans.py} (83%) + rename bin/tests/system/{repro_5874_nsec3_parent => nsec3_impersonation}/ns2/named.conf.j2 (90%) + rename bin/tests/system/{repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py => nsec3_impersonation/tests_nsec3_impersonation.py} (84%) + delete mode 100644 bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py + +diff --git a/bin/tests/system/repro_5874_nsec3_parent/server.py b/bin/tests/system/nsec3_impersonation/ans1/ans.py +similarity index 83% +rename from bin/tests/system/repro_5874_nsec3_parent/server.py +rename to bin/tests/system/nsec3_impersonation/ans1/ans.py +index c6856bb..177e79c 100644 +--- a/bin/tests/system/repro_5874_nsec3_parent/server.py ++++ b/bin/tests/system/nsec3_impersonation/ans1/ans.py +@@ -23,9 +23,9 @@ import dns.dnssec + import dns.flags + import dns.message + import dns.name ++import dns.rcode + import dns.rdata + import dns.rdataclass +-import dns.rcode + import dns.rdatatype + import dns.rrset + +@@ -141,10 +141,21 @@ def answer_ns( + add_signed(response.answer, ns_rrset(zone, ns_target), zone_key) + + +-def answer_ds( +- response: dns.message.Message, zone: str, child_key: Key, parent_key: Key +-) -> None: +- add_signed(response.answer, ds_rrset(zone, child_key), parent_key) ++class SignedResponseHandler(ResponseHandler): ++ def __init__(self, keys: dict[str, Key]) -> None: ++ self.keys = keys ++ ++ async def get_responses( ++ self, qctx: QueryContext ++ ) -> AsyncGenerator[DnsResponseSend, None]: ++ qctx.prepare_new_response(with_zone_data=False) ++ qctx.response.flags |= dns.flags.AA ++ qctx.response.set_rcode(dns.rcode.NOERROR) ++ self.respond(qctx) ++ yield DnsResponseSend(qctx.response, authoritative=True) ++ ++ def respond(self, qctx: QueryContext) -> None: ++ raise NotImplementedError + + + def child_nsec3_rrset() -> dns.rrset.RRset: +@@ -162,28 +173,15 @@ def forged_nxdomain(response: dns.message.Message, keys: dict[str, Key]) -> None + add_signed(response.authority, soa_rrset(TLD), keys[TLD]) + + # The owner name derives zone "tld.test.", but the RRSIG signer is the +- # secure child zone "1b40241kforiog780n4ikscrlvetpctq.tld.test.". ++ # malicious child zone "1b40241kforiog780n4ikscrlvetpctq.tld.test.". + add_signed(response.authority, child_nsec3_rrset(), keys[ATTACKER]) + + +-class SignedResponseHandler(ResponseHandler): +- def __init__(self, keys: dict[str, Key]) -> None: +- self.keys = keys +- +- async def get_responses( +- self, qctx: QueryContext +- ) -> AsyncGenerator[DnsResponseSend, None]: +- qctx.prepare_new_response(with_zone_data=False) +- qctx.response.flags |= dns.flags.AA +- qctx.response.set_rcode(dns.rcode.NOERROR) +- self.respond(qctx) +- yield DnsResponseSend(qctx.response, authoritative=True) +- +- def respond(self, qctx: QueryContext) -> None: +- raise NotImplementedError +- +- + class VictimForgedNxdomainHandler(SignedResponseHandler): ++ """ ++ This serves the forged response for the victim's domain. ++ """ ++ + def match(self, qctx: QueryContext) -> bool: + return qctx.qname == name(VICTIM) and qctx.qtype == dns.rdatatype.A + +@@ -192,14 +190,31 @@ class VictimForgedNxdomainHandler(SignedResponseHandler): + + + class ChildDsHandler(SignedResponseHandler): ++ """ ++ This will spoof the response for the malicious zone when qtype is DS. ++ It is actually a validly signed DS response. ++ """ ++ + def match(self, qctx: QueryContext) -> bool: + return qctx.qname == name(ATTACKER) and qctx.qtype == dns.rdatatype.DS + + def respond(self, qctx: QueryContext) -> None: +- answer_ds(qctx.response, ATTACKER, self.keys[ATTACKER], self.keys[TLD]) ++ response = qctx.response ++ zone = ATTACKER ++ child_key = self.keys[ATTACKER] ++ parent_key = self.keys[TLD] ++ ++ add_signed(response.answer, ds_rrset(zone, child_key), parent_key) + + + class AttackerZoneHandler(SignedResponseHandler): ++ """ ++ Acts as the malicious authoritative name server. The zone being served ++ is the hashed label of the parent zone (tld.test). This will respond ++ for all queries qtype SOA, DNSKEY, NS at the apex. Any names below ++ the apex are answered with an NXDOMAIN with no NSEC or NSEC3 present. ++ """ ++ + def match(self, qctx: QueryContext) -> bool: + return qctx.qname.is_subdomain(name(ATTACKER)) + +@@ -210,7 +225,9 @@ class AttackerZoneHandler(SignedResponseHandler): + elif qctx.qtype == dns.rdatatype.SOA: + answer_soa(qctx.response, ATTACKER, self.keys[ATTACKER]) + else: +- answer_ns(qctx.response, ATTACKER, f"ns.{ATTACKER}", self.keys[ATTACKER]) ++ answer_ns( ++ qctx.response, ATTACKER, f"ns.{ATTACKER}", self.keys[ATTACKER] ++ ) + qctx.response.additional.append(glue_rrset(f"ns.{ATTACKER}", AUTH_IP)) + return + +@@ -219,6 +236,16 @@ class AttackerZoneHandler(SignedResponseHandler): + + + class TldZoneHandler(SignedResponseHandler): ++ """ ++ Acts as the TLD who is being used in the attack, but is not a standard ++ name server. It only responds with validly signed records for DNSKEY, SOA ++ and NS on the apex. Any names below the apex are answered with an NXDOMAIN ++ with no NSEC or NSEC3 present. ++ ++ If we turn this into a regular name server than the attack won't work. ++ The attack assumes that the adversary can inject these responses on-path. ++ """ ++ + def match(self, qctx: QueryContext) -> bool: + return qctx.qname.is_subdomain(name(TLD)) + +@@ -247,3 +274,7 @@ def main() -> None: + TldZoneHandler(keys), + ) + server.run() ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 b/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 +similarity index 90% +rename from bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 +rename to bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 +index 9358866..2c9b0bb 100644 +--- a/bin/tests/system/repro_5874_nsec3_parent/ns2/named.conf.j2 ++++ b/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 +@@ -10,8 +10,6 @@ options { + listen-on-v6 { none; }; + recursion yes; + dnssec-validation yes; +- trust-anchor-telemetry no; +- resolver-query-timeout 5000; + }; + + controls { +diff --git a/bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py b/bin/tests/system/nsec3_impersonation/tests_nsec3_impersonation.py +similarity index 84% +rename from bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py +rename to bin/tests/system/nsec3_impersonation/tests_nsec3_impersonation.py +index 5fbeff5..bd9bd27 100644 +--- a/bin/tests/system/repro_5874_nsec3_parent/tests_repro_5874_nsec3_parent.py ++++ b/bin/tests/system/nsec3_impersonation/tests_nsec3_impersonation.py +@@ -26,6 +26,7 @@ import dns.rdatatype + import pytest + + import isctest ++import isctest.mark + + APEX_HASH = "1B40241KFORIOG780N4IKSCRLVETPCTQ" + ATTACKER = f"{APEX_HASH.lower()}.tld.test." +@@ -33,12 +34,15 @@ VICTIM = "victim.tld.test." + AUTH = "10.53.0.1" + RESOLVER = "10.53.0.2" + +-pytestmark = pytest.mark.extra_artifacts( +- [ +- "ans*/ans.run", +- "keys.json", +- ] +-) ++pytestmark = [ ++ isctest.mark.with_ecdsa_deterministic, ++ pytest.mark.extra_artifacts( ++ [ ++ "ans*/ans.run", ++ "ans*/keys.json", ++ ] ++ ), ++] + + + def _make_key(zone): +@@ -65,13 +69,13 @@ def bootstrap(): + zones = ["tld.test.", ATTACKER] + keys = {zone: _make_key(zone) for zone in zones} + +- Path("keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") ++ Path("ans1/keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") + + tld_dnskey = "".join(keys["tld.test."]["dnskey"].split()[3:]) + return {"TLD_DNSKEY": tld_dnskey} + + +-def _check_direct_dnskey_response(zone): ++def check_dnskey_response(zone): + query = isctest.query.create(zone, "DNSKEY") + response = isctest.query.tcp(query, AUTH) + +@@ -88,7 +92,7 @@ def _check_direct_dnskey_response(zone): + ), response + + +-def _check_direct_ds_response(zone): ++def check_ds_response(zone): + query = isctest.query.create(zone, "DS") + response = isctest.query.tcp(query, AUTH) + +@@ -105,10 +109,10 @@ def _check_direct_ds_response(zone): + ), response + + +-def test_repro_5874_direct_forged_nsec3_response_has_child_signer(): +- _check_direct_dnskey_response("tld.test.") +- _check_direct_dnskey_response(ATTACKER) +- _check_direct_ds_response(ATTACKER) ++def test_attack_responses(): ++ check_dnskey_response("tld.test.") ++ check_dnskey_response(ATTACKER) ++ check_ds_response(ATTACKER) + + query = isctest.query.create(VICTIM, "A") + response = isctest.query.tcp(query, AUTH) +@@ -136,9 +140,13 @@ def test_repro_5874_direct_forged_nsec3_response_has_child_signer(): + assert rrsig[0].signer == dns.name.from_text(ATTACKER) + + +-def test_repro_5874_resolver_rejects_child_signed_nsec3_parent_proof(): ++def test_nsec3_impersonation(): ++ """ ++ Reproducer for #5874: ++ F-006 DNSSEC Validation Bypass NSEC3 Apex Hash Label Parent Impersonation ++ """ + query = isctest.query.create(VICTIM, "A") + response = isctest.query.tcp(query, RESOLVER) + +- isctest.check.servfail(response) + isctest.check.noadflag(response) ++ isctest.check.servfail(response) +diff --git a/bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py b/bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py +deleted file mode 100644 +index 614f26a..0000000 +--- a/bin/tests/system/repro_5874_nsec3_parent/ans1/ans.py ++++ /dev/null +@@ -1,18 +0,0 @@ +-#!/usr/bin/python3 +- +-# 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 server import main +- +- +-if __name__ == "__main__": +- main() diff --git a/meta/recipes-connectivity/bind/bind_9.18.49.bb b/meta/recipes-connectivity/bind/bind_9.18.49.bb index 723a09e739..161736f9b1 100644 --- a/meta/recipes-connectivity/bind/bind_9.18.49.bb +++ b/meta/recipes-connectivity/bind/bind_9.18.49.bb @@ -18,6 +18,9 @@ SRC_URI = "https://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.xz \ file://bind-ensure-searching-for-json-headers-searches-sysr.patch \ file://0001-named-lwresd-V-and-start-log-hide-build-options.patch \ file://0001-avoid-start-failure-with-bind-user.patch \ + file://CVE-2026-10723-01.patch \ + file://CVE-2026-10723-02.patch \ + file://CVE-2026-10723-03.patch \ " SRC_URI[sha256sum] = "c43ce4548ebed788cd9df63658a7de105ceafba43fcd63fa352b1093e525cd24" From patchwork Mon Sep 28 07:11:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 99449 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A201DC9832F for ; Mon, 28 Sep 2026 07:12:40 +0000 (UTC) Received: from mail-dy2-f42.google.com (mail-dy2-f42.google.com [74.125.229.42]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.52911.1790579557375409581 for ; Mon, 28 Sep 2026 00:12:37 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=ZQEUuYz2; spf=pass (domain: mvista.com, ip: 74.125.229.42, mailfrom: hprajapati@mvista.com) Received: by mail-dy2-f42.google.com with SMTP id 5a478bee46e88-34182b58d00so1822123eec.2 for ; Mon, 28 Sep 2026 00:12:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1790579556; x=1791184356; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=1eygcCMZgJ2yn+BaJ17GcwKycpkdeubjEUrnR7R+ptM=; b=ZQEUuYz2pHsNAw5rUOX4wzvfyxUrqL9KU40nAum7yy1GkGpDjfaDXSi6DAu0yN2l4i +MCbB/dkXQaUTQOi5taDnuktqDyEUqfGIfDOgtICmIRge4ge+qvcgRHNZsKddEry+hjZ Lphu/dgd1ltCmBNl7KJHqHu5q80q30vHfUPuE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790579556; x=1791184356; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=1eygcCMZgJ2yn+BaJ17GcwKycpkdeubjEUrnR7R+ptM=; b=f6MFhik2hx2tTURlBfsnrMzJeXQDG4G3rL5uk3F85hVziyjjQUM2Qi0I2GypSeaD5T yM0jIbUFsw6z2FJ8Etgx0tOvrsnY+WALAuIHGHyoOzaxj0tP6KMV9b5pMCB+UL/MkFQl iyIXeEv7ODWC2IYAOPep8+HiaMDT4mGQqJhcEdSzw4jWVs8b6QbuTqaXQO7tft18LgUm bQrk3mqLfSEXBOUoIWalto6rTWG2n2mzcttJ+3zQSCQtfMl+kGZxR9nierSnjcSSioGl +qOih+w6joW+mamKmdqeM8fQXONBPj79PXHVfUt34PgIBxZG6wzO5P8OUaM5V7GVl1rF jBjA== X-Gm-Message-State: AFq9FYJ3RzBv5mnGaQyTegzliHu6gH/Hy4T04J/zrGtd/tODFjv+nigi 5DTFWfN//9JK5axl7LMiscQH+IL45cNMp5G9Km7VPhtSzEmaEU2IpFuZGz2J8NT8GbCr//jTm2Q EVU7NWTU= X-Gm-Gg: AYBFou1qkfVYrgcD++Y99hu9GFUJ1tfGYRiiJilgiuwPX34ktZhv9Xe7VwF/yCJF2Xt FtJLeDRxcOjKnesn0KaSXrgIBO9hAU2CbZVs3JnooC1Wehe5VM3+jlUWK3O0wIIiK/0wxNoK/Dl Z1/EiFbNnuld77q8InZ3vlU+geaWAT3pORMLc7ExTHMZI/n21tgzuOENC7aWcaVZKK16NZqxxTJ n8MuzRlmBDQbIOjuIoI8a/Rnhdf/d1DCVw4v6doZzu9khptc/vcMR7O4PcHen5o9VGwFbD5T5Tx 063jFNzd9CgWge0pud1wUdovczMVxjtVLDWC9fg8AgyBpEZbQQ/bcW7ExbnzV4eVL7mi8hyb2h5 xIN4zXwdeJ2FsuwhuAE1A+tDpdl6SbZdAAsHlK7cz3Qe1aMWYt2G6j2itl8HV+mhfGU1BMcTb+h El8WXv3lYdOmC3/0KOC9yFtEctZ72U8e0499Jj0K6bTF86OtFvmufPom6K+nshi7QQMXnR8co2B rqrH0KmG9dw X-Received: by 2002:a05:693c:8948:20b0:332:8b9b:bdc4 with SMTP id 5a478bee46e88-3427324d765mr8068025eec.20.1790579556250; Mon, 28 Sep 2026 00:12:36 -0700 (PDT) Received: from MVIN00013.mvista.com ([150.129.170.212]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3434958c3adsm31166948eec.22.2026.09.28.00.12.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2026 00:12:35 -0700 (PDT) From: Hitendra Prajapati To: openembedded-core@lists.openembedded.org Cc: Hitendra Prajapati Subject: [scarthgap][PATCH 2/6] bind: fix for CVE-2026-10822 Date: Mon, 28 Sep 2026 12:41:07 +0530 Message-ID: <20260928071115.304055-2-hprajapati@mvista.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260928071115.304055-1-hprajapati@mvista.com> References: <20260928071115.304055-1-hprajapati@mvista.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 07:12:40 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/246732 Pick patch from [1], [2], [3], [4] & [5] also mentioned at Debian report in [6] [1] https://gitlab.isc.org/isc-projects/bind9/-/commit/d413c9ac2e29a728531354a69c8c8234c01b7d1e [2] https://gitlab.isc.org/isc-projects/bind9/-/commit/a5f1a9d0d2ec021618924b14202ac96ead8299c1 [3] https://gitlab.isc.org/isc-projects/bind9/-/commit/e73b70a64453e7d97a11cb5f0afe8bb02d34aaf8 [4] https://gitlab.isc.org/isc-projects/bind9/-/commit/19ac8b8e46aeb0a15e217bc7bdf485b31b87d9b4 [5] https://gitlab.isc.org/isc-projects/bind9/-/commit/8e066d3fc369e3346f22bb5cfb67a7ab08a74034 [6] https://security-tracker.debian.org/tracker/CVE-2026-10822 Signed-off-by: Hitendra Prajapati --- .../bind/bind/CVE-2026-10822-01.patch | 69 ++++++ .../bind/bind/CVE-2026-10822-02.patch | 33 +++ .../bind/bind/CVE-2026-10822-03.patch | 35 +++ .../bind/bind/CVE-2026-10822-04.patch | 53 +++++ .../bind/bind/CVE-2026-10822-05.patch | 223 ++++++++++++++++++ .../recipes-connectivity/bind/bind_9.18.49.bb | 5 + 6 files changed, 418 insertions(+) create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10822-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10822-02.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10822-03.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10822-04.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-10822-05.patch diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-10822-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-01.patch new file mode 100644 index 0000000000..1c330418a6 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-01.patch @@ -0,0 +1,69 @@ +From: Mark Andrews +Date: Tue, 19 May 2026 10:44:04 +1000 +Subject: 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) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/d413c9ac2e29a728531354a69c8c8234c01b7d1e +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10822 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10822 + +CVE: CVE-2026-10822 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/d413c9ac2e29a728531354a69c8c8234c01b7d1e] +Signed-off-by: Hitendra Prajapati +--- + tests/dns/name_test.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/tests/dns/name_test.c b/tests/dns/name_test.c +index fb34dca..95f6598 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/meta/recipes-connectivity/bind/bind/CVE-2026-10822-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-02.patch new file mode 100644 index 0000000000..0735bafadd --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-02.patch @@ -0,0 +1,33 @@ +From: Mark Andrews +Date: Tue, 19 May 2026 15:00:17 +1000 +Subject: 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) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/a5f1a9d0d2ec021618924b14202ac96ead8299c1 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10822 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10822 + +CVE: CVE-2026-10822 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/a5f1a9d0d2ec021618924b14202ac96ead8299c1] +Signed-off-by: Hitendra Prajapati +--- + bin/tools/dnstap-read.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/bin/tools/dnstap-read.c b/bin/tools/dnstap-read.c +index a1d0243..bb78ae1 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/meta/recipes-connectivity/bind/bind/CVE-2026-10822-03.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-03.patch new file mode 100644 index 0000000000..5708c06d9f --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-03.patch @@ -0,0 +1,35 @@ +From: Mark Andrews +Date: Tue, 19 May 2026 11:12:46 +1000 +Subject: 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) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/e73b70a64453e7d97a11cb5f0afe8bb02d34aaf8 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10822 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10822 + +CVE: CVE-2026-10822 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/e73b70a64453e7d97a11cb5f0afe8bb02d34aaf8] +Signed-off-by: Hitendra Prajapati +--- + lib/dns/name.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/dns/name.c b/lib/dns/name.c +index cc0e30e..2ce868a 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; diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-10822-04.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-04.patch new file mode 100644 index 0000000000..ff5a8811f0 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-04.patch @@ -0,0 +1,53 @@ +From: Mark Andrews +Date: Tue, 19 May 2026 12:03:23 +1000 +Subject: 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) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/19ac8b8e46aeb0a15e217bc7bdf485b31b87d9b4 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10822 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10822 + +CVE: CVE-2026-10822 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/19ac8b8e46aeb0a15e217bc7bdf485b31b87d9b4] +Signed-off-by: Hitendra Prajapati +--- + tests/dns/rdata_test.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/tests/dns/rdata_test.c b/tests/dns/rdata_test.c +index 6354819..7f0df6e 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); + } + + /* diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-10822-05.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-05.patch new file mode 100644 index 0000000000..41a6588045 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-10822-05.patch @@ -0,0 +1,223 @@ +From: Mark Andrews +Date: Fri, 5 Jun 2026 09:18:30 +1000 +Subject: 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) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/8e066d3fc369e3346f22bb5cfb67a7ab08a74034 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-10822 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-10822 + +CVE: CVE-2026-10822 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/8e066d3fc369e3346f22bb5cfb67a7ab08a74034] +Signed-off-by: Hitendra Prajapati +--- + bin/tests/system/xfer/ans9/ans.py | 142 ++++++++++++++++++++++++++++++++ + bin/tests/system/xfer/ns6/named.conf.in | 9 ++ + bin/tests/system/xfer/tests.sh | 16 ++++ + 3 files changed, 167 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 0000000..a9e7395 +--- /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 142383c..6380944 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 a2c0adb..e08be17 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/meta/recipes-connectivity/bind/bind_9.18.49.bb b/meta/recipes-connectivity/bind/bind_9.18.49.bb index 161736f9b1..42007383c4 100644 --- a/meta/recipes-connectivity/bind/bind_9.18.49.bb +++ b/meta/recipes-connectivity/bind/bind_9.18.49.bb @@ -21,6 +21,11 @@ SRC_URI = "https://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.xz \ file://CVE-2026-10723-01.patch \ file://CVE-2026-10723-02.patch \ file://CVE-2026-10723-03.patch \ + file://CVE-2026-10822-01.patch \ + file://CVE-2026-10822-02.patch \ + file://CVE-2026-10822-03.patch \ + file://CVE-2026-10822-04.patch \ + file://CVE-2026-10822-05.patch \ " SRC_URI[sha256sum] = "c43ce4548ebed788cd9df63658a7de105ceafba43fcd63fa352b1093e525cd24" From patchwork Mon Sep 28 07:11:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 99450 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9EF86C9832F for ; Mon, 28 Sep 2026 07:13:10 +0000 (UTC) Received: from mail-dy2-f12.google.com (mail-dy2-f12.google.com [74.125.229.12]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.52916.1790579580745914995 for ; Mon, 28 Sep 2026 00:13:00 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=L2IoBN+u; spf=pass (domain: mvista.com, ip: 74.125.229.12, mailfrom: hprajapati@mvista.com) Received: by mail-dy2-f12.google.com with SMTP id 5a478bee46e88-328664dbe2dso1453450eec.0 for ; Mon, 28 Sep 2026 00:13:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1790579580; x=1791184380; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=5HTnTByutD3xTzJwoXTkLnKqSJoTvkf0PIaoc15qD/c=; b=L2IoBN+uLiOzLpFsdYmUkto/y7SzuP91sOZUlANY9mrt6OmqrUtEmwYp0lsjXOw3G5 +2sdacbPgcwRf92LP7xfdbmYtaEApllAdkq1jROvZnQIrhgNwOzgfTaw1qQLOXcGdsr4 E1EQyY7QCE/iC3gcAmwdQ6ovYhG7bWLyXQrcc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790579580; x=1791184380; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=5HTnTByutD3xTzJwoXTkLnKqSJoTvkf0PIaoc15qD/c=; b=pvBtLNTpjwV2279cltsN4KX2i/dV23O+8iUDk2Lt0IMopVPCiwqki0Z5r+LnZ9ngO1 Fz8x+71+RcUeR2gCQbRR6PPkeYjO6IUG4Dn04WShkNGCnRswW6QWARQKppoTK7T+fD16 1NHvBv5HHRNj/JqIRSMQ8ykWcRlzD6aq42Z0q45a/aaI2TM9pQkXOvMvVeGhUNoLPP47 nSduKuY9bt9fTC7+B9j0KClJExhdqdgo+aDp3xTu15hGGme5bbY8xKvtx1lwG7tRe3ME KQ+pj+gOfGnD5v+2JIc25fmAtD006vSqKs9JSrOayXbNftEIMq530l7zQGDngi2KpUpJ PUxw== X-Gm-Message-State: AFq9FYJmzSa4dW9UZtX2sz14+VVySGHub452J3jmzq72T3XJVGbOceb1 fLU4Giw2xIs1I+HL8vPmNZOTymny8qdFcnmv91fOXCoAaedNzvLuIwOnrUNt11KQe1Lw4WONw1u pKSDe9yk= X-Gm-Gg: AYBFou0GZprjoIWdnhK7/aElW9mR06mGccDoHOktOFLjM9VPVMWS+w5PJE+Te/d33Mc b6TYuhhFYAJI6XfXmBphQb7EWYdaBN0k4uA0+iOmr1zsBwITuaNHNNxFHvSAJwcaoCqnIIvoe4y DtUvR2tv3TdQYxiKzs54z0WOSchhifk2MTFzxjoZoeNQDJTGIJ3ZG6k92QN47qPNDcyE6P/5P+Q /vn3DgLNa2XALSRgGGfGprtafMCi/vRS4iyY3yGrNBZH1f0Kda+x4tYJWtbEfFIcyg9fttJa/Vy +XWg6gzEbLW2rT2XCU6/cIKyZLlGqs4SndLz/8gPJ936bqOGWdO7Ltg/HhaBYjEgrWGl/mVAB8Z aORGONkNkXfhkdzRP0baD4QFP4FhfcbOBTARf+UXuvLWHK1TCrS9bn+xsSKwIJkJdpwQbeo7v8o 9Q75wSizSnztPqLazb4z/Fts7RwK5NhqpKHT6z/1hXjx30Z1VXMmTBwYaYy92WTUiegFbCfc7vm Rn2PvUiCMs= X-Received: by 2002:a05:7301:2727:b0:332:94e9:a72e with SMTP id 5a478bee46e88-34272754c58mr9337203eec.9.1790579579843; Mon, 28 Sep 2026 00:12:59 -0700 (PDT) Received: from MVIN00013.mvista.com ([150.129.170.212]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3434958c3adsm31166948eec.22.2026.09.28.00.12.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2026 00:12:59 -0700 (PDT) From: Hitendra Prajapati To: openembedded-core@lists.openembedded.org Cc: Hitendra Prajapati Subject: [scarthgap][PATCH 3/6] bind: fix for CVE-2026-11331 Date: Mon, 28 Sep 2026 12:41:08 +0530 Message-ID: <20260928071115.304055-3-hprajapati@mvista.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260928071115.304055-1-hprajapati@mvista.com> References: <20260928071115.304055-1-hprajapati@mvista.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 07:13:10 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/246733 Pick patch from [1], [2] & [3] also mentioned at Debian report in [4] [1] https://gitlab.isc.org/isc-projects/bind9/-/commit/adc8285d23e2eac6ec463f5dbc5a9596fdd36c60 [2] https://gitlab.isc.org/isc-projects/bind9/-/commit/095b11f20f911f5b8059bdc349b256d6c64ece30 [3] https://gitlab.isc.org/isc-projects/bind9/-/commit/dc328a199f96222e0c30cc20b7b795bfc2c9b2e4 [4] https://security-tracker.debian.org/tracker/CVE-2026-11331 Signed-off-by: Hitendra Prajapati --- .../bind/bind/CVE-2026-11331-01.patch | 30 ++++++++++ .../bind/bind/CVE-2026-11331-02.patch | 58 +++++++++++++++++++ .../bind/bind/CVE-2026-11331-03.patch | 34 +++++++++++ .../recipes-connectivity/bind/bind_9.18.49.bb | 3 + 4 files changed, 125 insertions(+) create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11331-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11331-02.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11331-03.patch diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11331-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11331-01.patch new file mode 100644 index 0000000000..1aaca7392a --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11331-01.patch @@ -0,0 +1,30 @@ +From: Mark Andrews +Date: Fri, 10 Apr 2026 10:24:06 +1000 +Subject: Fix TTL extraction from A/AAAA record + +(cherry picked from commit 89c86e338db2492b92e6618c586f146c6928dc6d) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/adc8285d23e2eac6ec463f5dbc5a9596fdd36c60 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11331 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11331 + +CVE: CVE-2026-11331 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/adc8285d23e2eac6ec463f5dbc5a9596fdd36c60] +Signed-off-by: Hitendra Prajapati +--- + bin/tests/system/rpz/tests.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bin/tests/system/rpz/tests.sh b/bin/tests/system/rpz/tests.sh +index 87e4118..90cf80c 100644 +--- a/bin/tests/system/rpz/tests.sh ++++ b/bin/tests/system/rpz/tests.sh +@@ -391,7 +391,7 @@ addr() { + digcmd $2 >$DIGNM + #ckalive "$2" "server crashed by 'dig $2'" || return 1 + ADDR_ESC=$(echo "$ADDR" | sed -e 's/\./\\./g') +- ADDR_TTL=$(sed -n -e "s/^[-.a-z0-9]\{1,\}[ ]*\([0-9]*\) IN AA* ${ADDR_ESC}\$/\1/p" $DIGNM) ++ ADDR_TTL=$(sed -n -e "s/^[-.a-z0-9]\{1,\}[ ]*\([0-9]*\)[ ]IN[ ]AA*[ ]${ADDR_ESC}\$/\1/p" $DIGNM) + if test -z "$ADDR_TTL"; then + setret "'dig $2' wrong; no address $ADDR record in $DIGNM" + return 0 diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11331-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11331-02.patch new file mode 100644 index 0000000000..8f45d7021b --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11331-02.patch @@ -0,0 +1,58 @@ +From: Mark Andrews +Date: Fri, 10 Apr 2026 10:24:40 +1000 +Subject: Check rpz name too long wildcard CNAME expansion handling + +(cherry picked from commit 9345394e2097031b55b3ef34ceaadf5a7ebbeef2) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/095b11f20f911f5b8059bdc349b256d6c64ece30 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11331 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11331 + +CVE: CVE-2026-11331 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/095b11f20f911f5b8059bdc349b256d6c64ece30] +Signed-off-by: Hitendra Prajapati +--- + bin/tests/system/rpz/ns2/tld2.db | 2 ++ + bin/tests/system/rpz/ns4/tld4.db | 2 ++ + bin/tests/system/rpz/tests.sh | 5 ++++- + 3 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/bin/tests/system/rpz/ns2/tld2.db b/bin/tests/system/rpz/ns2/tld2.db +index c6f2556..c091ee2 100644 +--- a/bin/tests/system/rpz/ns2/tld2.db ++++ b/bin/tests/system/rpz/ns2/tld2.db +@@ -123,3 +123,5 @@ a7-1 A 192.168.7.1 + + a7-2 A 192.168.7.2 + TXT "a7-2 tld2 text" ++ ++*.wild A 192.168.9.1 +diff --git a/bin/tests/system/rpz/ns4/tld4.db b/bin/tests/system/rpz/ns4/tld4.db +index fca419c..8accd76 100644 +--- a/bin/tests/system/rpz/ns4/tld4.db ++++ b/bin/tests/system/rpz/ns4/tld4.db +@@ -59,6 +59,8 @@ a3-6.tld2 A 56.56.56.56 + + a3-7.sub1.tld2 A 57.57.57.57 + ++*.wild.sub1.tld2 A 57.57.57.57 ++ + a3-8.tld2 A 58.58.58.58 + + a3-9.sub9.tld2 A 59.59.59.59 +diff --git a/bin/tests/system/rpz/tests.sh b/bin/tests/system/rpz/tests.sh +index 90cf80c..5297437 100644 +--- a/bin/tests/system/rpz/tests.sh ++++ b/bin/tests/system/rpz/tests.sh +@@ -516,7 +516,10 @@ nochange TCP a3-9.tld2 # 33 tcp-only + here x.servfail <<'EOF' # 34 qname-wait-recurse yes + ;; status: SERVFAIL, x + EOF +-addr 35.35.35.35 "x.servfail @$ns5" # 35 qname-wait-recurse no ++addr 35.35.35.35 "x.servfail @$ns5" # 35 qname-wait-recurse no ++here aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.wild.sub1.tld2 <<'EOF' # 36 wildcard CNAME name to long ++ ;; status: YXDOMAIN, x ++EOF + end_group + ckstats $ns3 test1 ns3 22 + ckstats $ns5 test1 ns5 1 diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11331-03.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11331-03.patch new file mode 100644 index 0000000000..2d57122632 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11331-03.patch @@ -0,0 +1,34 @@ +From: Mark Andrews +Date: Fri, 10 Apr 2026 10:26:14 +1000 +Subject: Properly handle rpz name to long wildcard expansion + +Previously a self referential CNAME and the original address +record were returned. We now return a YXDOMAIN response. + +(cherry picked from commit cfc4c4f69870ce492deaaa429453563d1621ded3) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/dc328a199f96222e0c30cc20b7b795bfc2c9b2e4 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11331 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11331 + +CVE: CVE-2026-11331 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/dc328a199f96222e0c30cc20b7b795bfc2c9b2e4] +Signed-off-by: Hitendra Prajapati +--- + lib/ns/query.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/lib/ns/query.c b/lib/ns/query.c +index 86485b7..f0e5244 100644 +--- a/lib/ns/query.c ++++ b/lib/ns/query.c +@@ -7579,7 +7579,8 @@ query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) { + qctx->fname, NULL); + if (result == DNS_R_NAMETOOLONG) { + client->message->rcode = dns_rcode_yxdomain; +- } else if (result != ISC_R_SUCCESS) { ++ } ++ if (result != ISC_R_SUCCESS) { + return result; + } + } else { diff --git a/meta/recipes-connectivity/bind/bind_9.18.49.bb b/meta/recipes-connectivity/bind/bind_9.18.49.bb index 42007383c4..dc274f6076 100644 --- a/meta/recipes-connectivity/bind/bind_9.18.49.bb +++ b/meta/recipes-connectivity/bind/bind_9.18.49.bb @@ -26,6 +26,9 @@ SRC_URI = "https://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.xz \ file://CVE-2026-10822-03.patch \ file://CVE-2026-10822-04.patch \ file://CVE-2026-10822-05.patch \ + file://CVE-2026-11331-01.patch \ + file://CVE-2026-11331-02.patch \ + file://CVE-2026-11331-03.patch \ " SRC_URI[sha256sum] = "c43ce4548ebed788cd9df63658a7de105ceafba43fcd63fa352b1093e525cd24" From patchwork Mon Sep 28 07:11:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 99451 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A79E6C9833E for ; Mon, 28 Sep 2026 07:13:30 +0000 (UTC) Received: from mail-dy2-f43.google.com (mail-dy2-f43.google.com [74.125.229.43]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.52921.1790579608703059554 for ; Mon, 28 Sep 2026 00:13:28 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=kYbEhB9b; spf=pass (domain: mvista.com, ip: 74.125.229.43, mailfrom: hprajapati@mvista.com) Received: by mail-dy2-f43.google.com with SMTP id 5a478bee46e88-33e630052ebso3248037eec.0 for ; Mon, 28 Sep 2026 00:13:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1790579608; x=1791184408; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Q+ntmjJj3uS06rnAVpl7HLalwRFeNmFzjAs4JYfmy/E=; b=kYbEhB9bREQNXvZKgOrS3/QWiJnGse55tBRpcMuakiVI1YI5cL66klYdHYCCWdOy3M r8QxOI2sZZRT5u+91Fcbkj/yixj6Ztin4v0wh78v1mecEL08RMWbTZNsZ0E1U4/l/psI Iar2eGhV4Oh/i7zb1LPvegxEF2xRZodnycOa8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790579608; x=1791184408; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Q+ntmjJj3uS06rnAVpl7HLalwRFeNmFzjAs4JYfmy/E=; b=IKuIDA38PgjK42bUCfJCWNyqaJSkp5Y/YcOCFuREbnUDrkADW5Zq3CLSgW10l8RbJG J10tA2NOY3E80UtS4MhxU7J6Yx/bW1b6WIWKNbcsrlr9g5L1VAbsN42xvLLBjlire0pa XKz9jhV953YIo7CAyM4qfUyppwxvnWy+R5SF+4+XtE1j8x472Sb1f3MdV0w02mFmB2Fu BVx+lnnw8VXTtqnX/xHwlxZUyeOX1+TLYhj4WzIJtwGBlzPbXZ+xyrnCNz6Prp9nmoNP lmOK6YRclLzHWc1gRYyp3M7ESEva5YqPXBfCvqB8TylMHpMrs+XfCz55xtX5beAG9QdM twzQ== X-Gm-Message-State: AFq9FYIs+EWyyn8a83htfkoF5/8dEdcCYKwcZZf6tT2s/ujtYgSgbP14 +hB0dhFEhvrCquEtpmsbTZjhqLSNh/rN2J1XrHUBsQU1YcJKWUVdZZ5nfue9YZhkjApWh1dHudk y7/Bcyt0= X-Gm-Gg: AYBFou3tI/SJ5odKuAtMzxeZ358wbJ4ZPnL/LIJs63s9pCE/XJUnN+LOs9vwApA7aXz KsDgzfbgej2AihQYEdZAzmyCxEOaUpggyi8PJI+hXwTUAAV1X3eK41cNsqqPUhj5QbW4sNKfcDU KegxvgI6jt9eDGtaZjCKXgWK4kbOGoNSAnmL/KXjxh2Vnlj25pFLrGvJrSmBjAjrNrqfI0PL86Y jl/1pAMLXCLKad8CJGt1d7f+KzaBz/FuYhzCR5d85k2WnG/pU26jWZT3bYjsL9HqFw1MencNRA6 n+WQesJzVrgMtOrzoodEmb7kmERWur1azBJiV5guO3SLbolJ1EgeRYCN1ILoinTwtXMa6bcEySl TQTzakeXcI3LUASdO/1yeCjwF6bzVf/6e6beW7ClH+RbB2az+zjv45srgd3TAC5SwaBbz5F/BmF uncXxXAo/Yh+AN4POzIcfTMglRJwE0M03PVvIdRMfPd6UDxYHHQ8lcnX3FMOitjv9AeCn0Uts0J Eg21Pan3H4= X-Received: by 2002:a05:7301:1709:b0:33b:db21:9877 with SMTP id 5a478bee46e88-34271a92007mr8363489eec.20.1790579607660; Mon, 28 Sep 2026 00:13:27 -0700 (PDT) Received: from MVIN00013.mvista.com ([150.129.170.212]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3434958c3adsm31166948eec.22.2026.09.28.00.13.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2026 00:13:27 -0700 (PDT) From: Hitendra Prajapati To: openembedded-core@lists.openembedded.org Cc: Hitendra Prajapati Subject: [scarthgap][PATCH 4/6] bind: fix for CVE-2026-11622, CVE-2026-11721 Date: Mon, 28 Sep 2026 12:41:09 +0530 Message-ID: <20260928071115.304055-4-hprajapati@mvista.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260928071115.304055-1-hprajapati@mvista.com> References: <20260928071115.304055-1-hprajapati@mvista.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 07:13:30 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/246734 Pick patch from [1], [2], [3] & [4] also mentioned at Debian report in [5] & [6] [1] https://gitlab.isc.org/isc-projects/bind9/-/commit/231b1ca3edfb26389e1af39181aa6b4413e87ec4 [2] https://gitlab.isc.org/isc-projects/bind9/-/commit/1a4986e2533f87e80eb21da3f06708d335aff1e2 [3] https://gitlab.isc.org/isc-projects/bind9/-/commit/15089066b15f826d7487c3d160b5872820f84b83 [4] https://gitlab.isc.org/isc-projects/bind9/-/commit/19e496ca260b6a756ae1378e8ebcbdb666b7d9ed [5] https://security-tracker.debian.org/tracker/CVE-2026-11721 [6] https://security-tracker.debian.org/tracker/CVE-2026-11622 Signed-off-by: Hitendra Prajapati --- .../bind/bind/CVE-2026-11622.patch | 283 ++++++++++++++++++ .../bind/bind/CVE-2026-11721-01.patch | 43 +++ .../bind/bind/CVE-2026-11721-02.patch | 238 +++++++++++++++ .../bind/bind/CVE-2026-11721-03.patch | 147 +++++++++ .../recipes-connectivity/bind/bind_9.18.49.bb | 4 + 5 files changed, 715 insertions(+) create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11622.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11721-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11721-02.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-11721-03.patch diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11622.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11622.patch new file mode 100644 index 0000000000..9698762029 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11622.patch @@ -0,0 +1,283 @@ +From: =?utf-8?b?T25kxZllaiBTdXLDvQ==?= +Date: Tue, 23 Jun 2026 10:59:38 +0200 +Subject: Make the dns_slabheaders in the cache reference counted + +Instead of only reference counting the enclosing qpcnode, add the +reference counting directly to the slabheaders. The reference is +incremented when an rdataset is bound to the header and decremented when +the rdataset is disassociated, so a stale slabheader can be removed from +the node's down chain as soon as its own reference count reaches zero, +instead of waiting for the whole qpcnode to become unreferenced. + +Building on that, clean up the ancient headers eagerly: mark_ancient() +is made idempotent, releases the header's own (container) reference and +reaps the stale headers from the node's down chain as soon as their +references reach zero. A header evicted over the per-name type limit is +expired only after the new rdataset has been bound, so the bind's +increment always precedes mark_ancient()'s decrement. + +Because a header can now be reclaimed independently of its node, the +rdataset iterators must keep the header they are positioned on alive: +each iterator takes a reference on its current header and releases it +when it advances or is destroyed. Iteration otherwise stays lazy and +re-reads the node on every step, so it still observes records added to +the node while the iterator is live, as zone signing requires. + +The slab headers are shared with the zone databases, so the matching +increment is added to every bind path. The noqname/closest proofs hand +out rdatasets backed by bare slabs that have no header, so they are +given a separate dns_rdataproof_rdatasetmethods that leaves the +reference count untouched. + +(cherry picked from commit 2dabf117e1264fd13fb33096f87e78a039fd1c6c) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/231b1ca3edfb26389e1af39181aa6b4413e87ec4 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11622 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11622 + +CVE: CVE-2026-11622 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/231b1ca3edfb26389e1af39181aa6b4413e87ec4] +Signed-off-by: Hitendra Prajapati +--- + bin/tests/system/reclimit/tests.sh | 4 +- + lib/dns/include/dns/rdataslab.h | 1 + + lib/dns/rbtdb.c | 77 ++++++++++++++++++++++++++++++++------ + 3 files changed, 69 insertions(+), 13 deletions(-) + +diff --git a/bin/tests/system/reclimit/tests.sh b/bin/tests/system/reclimit/tests.sh +index 76889ec..efa7316 100644 +--- a/bin/tests/system/reclimit/tests.sh ++++ b/bin/tests/system/reclimit/tests.sh +@@ -337,13 +337,13 @@ echo_i "checking that NXDOMAIN names over the max-types-per-name limit don't get + + # Query for 10 NXDOMAIN types + for ntype in $(seq 65270 65279); do +- check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR big SOA 0 || ret=1 ++ check_manytypes 1 manytypes.big "TYPE${ntype}" NOERROR big SOA 120 || ret=1 + done + # Wait at least 1 second + sleep 1 + # Query for 10 NXDOMAIN types again - these should not be cached + for ntype in $(seq 65270 65279); do +- check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR big SOA 0 || ret=1 ++ check_manytypes 2 manytypes.big "TYPE${ntype}" NOERROR big SOA 120 || ret=1 + done + + if [ $ret -ne 0 ]; then echo_i "failed"; fi +diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h +index 5729c00..6bd3b59 100644 +--- a/lib/dns/include/dns/rdataslab.h ++++ b/lib/dns/include/dns/rdataslab.h +@@ -44,6 +44,7 @@ + #include + + #include ++#include + + #include + +diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c +index 62bc97d..0b85479 100644 +--- a/lib/dns/rbtdb.c ++++ b/lib/dns/rbtdb.c +@@ -158,6 +158,7 @@ struct noqname { + }; + + typedef struct rdatasetheader { ++ isc_refcount_t references; + /*% + * Locked by the owning node's lock. + */ +@@ -1447,6 +1448,7 @@ init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h) { + h->heap_index = 0; + atomic_init(&h->attributes, 0); + atomic_init(&h->last_refresh_fail_ts, 0); ++ isc_refcount_init(&h->references, 1); + + STATIC_ASSERT(sizeof(h->attributes) == 2, + "The .attributes field of rdatasetheader_t needs to be " +@@ -1559,6 +1561,9 @@ rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) { + } + } + ++static void ++clean_stale_headers(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *top); ++ + static void + mark_header_ancient(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) { + uint_least16_t attributes = atomic_load_acquire(&header->attributes); +@@ -1584,8 +1589,12 @@ mark_header_ancient(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) { + update_rrsetstats(rbtdb, header->type, attributes, false); + header->node->dirty = 1; + ++ isc_refcount_decrement(&header->references); ++ + /* Increment the stats counter for the ancient RRtype. */ + update_rrsetstats(rbtdb, header->type, newattributes, true); ++ ++ clean_stale_headers(rbtdb, rbtdb->common.mctx, header); + } + + static void +@@ -1621,12 +1630,19 @@ static void + clean_stale_headers(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, + rdatasetheader_t *top) { + rdatasetheader_t *d, *down_next; ++ rdatasetheader_t *down_parent = top; + + for (d = top->down; d != NULL; d = down_next) { + down_next = d->down; +- free_rdataset(rbtdb, mctx, d); ++ d->next = down_parent; ++ ++ if (isc_refcount_current(&d->references) == 0) { ++ free_rdataset(rbtdb, mctx, d); ++ down_parent->down = down_next; ++ } else { ++ down_parent = d; ++ } + } +- top->down = NULL; + } + + static void +@@ -1642,6 +1658,7 @@ clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { + for (current = node->data; current != NULL; current = top_next) { + top_next = current->next; + clean_stale_headers(rbtdb, mctx, current); ++ INSIST(current->down == NULL); + /* + * If current is nonexistent, ancient, or stale and + * we are not keeping stale, we can clean it up. +@@ -3114,6 +3131,8 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdatasetheader_t *header, + return; + } + ++ isc_refcount_increment(&header->references); ++ + dns__rbtnode_acquire(rbtdb, node, locktype); + + INSIST(rdataset->methods == NULL); /* We must be disassociated. */ +@@ -6307,6 +6326,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename, + bool header_nx; + bool newheader_nx; + bool merge; ++ bool do_expireheader = false; + dns_rdatatype_t rdtype, covers; + rbtdb_rdatatype_t negtype, sigtype; + dns_trust_t trust; +@@ -6856,6 +6876,7 @@ find_header: + } + + if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { ++ do_expireheader = true; + if (expireheader == NULL) { + expireheader = newheader; + } +@@ -6869,15 +6890,6 @@ find_header: + */ + expireheader = newheader; + } +- +- set_ttl(rbtdb, expireheader, 0); +- mark_header_ancient(rbtdb, expireheader); +- /* +- * FIXME: In theory, we should mark the RRSIG +- * and the header at the same time, but there is +- * no direct link between those two header, so +- * we would have to check the whole list again. +- */ + } + } + } +@@ -6901,6 +6913,15 @@ find_header: + isc_rwlocktype_write, addedrdataset); + } + ++ /* ++ * We need to delay the expiration of the header until we are bound to ++ * it to prevent decrement-then-increment on the header references. ++ */ ++ if (do_expireheader) { ++ set_ttl(rbtdb, expireheader, 0); ++ mark_header_ancient(rbtdb, expireheader); ++ } ++ + return ISC_R_SUCCESS; + } + +@@ -8692,6 +8713,12 @@ rdataset_disassociate(dns_rdataset_t *rdataset) { + dns_db_t *db = rdataset->private1; + dns_dbnode_t *node = rdataset->private2; + ++ if (rdataset->methods == &rdataset_methods) { ++ rdatasetheader_t *header = rdataset->private3; ++ header--; ++ isc_refcount_decrement(&header->references); ++ } ++ + detachnode(db, &node); + } + +@@ -8806,6 +8833,11 @@ rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { + dns_dbnode_t *cloned_node = NULL; + + attachnode(db, node, &cloned_node); ++ if (source->methods == &rdataset_methods) { ++ rdatasetheader_t *header = source->private3; ++ header--; ++ isc_refcount_increment(&header->references); ++ } + INSIST(!ISC_LINK_LINKED(target, link)); + *target = *source; + ISC_LINK_INIT(target, link); +@@ -8969,6 +9001,11 @@ rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) { + + rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp); + ++ if (rbtiterator->current != NULL) { ++ isc_refcount_decrement(&rbtiterator->current->references); ++ rbtiterator->current = NULL; ++ } ++ + if (rbtiterator->common.version != NULL) { + closeversion(rbtiterator->common.db, + &rbtiterator->common.version, false); +@@ -9046,9 +9083,18 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) { + } + } + ++ if (header != NULL) { ++ isc_refcount_increment0(&header->references); ++ } ++ + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, + isc_rwlocktype_read); + ++ if (rbtiterator->current != NULL) { ++ isc_refcount_decrement(&rbtiterator->current->references); ++ rbtiterator->current = NULL; ++ } ++ + rbtiterator->current = header; + + if (header == NULL) { +@@ -9140,9 +9186,18 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { + } + } + ++ if (header != NULL) { ++ isc_refcount_increment0(&header->references); ++ } ++ + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, + isc_rwlocktype_read); + ++ if (rbtiterator->current != NULL) { ++ isc_refcount_decrement(&rbtiterator->current->references); ++ rbtiterator->current = NULL; ++ } ++ + rbtiterator->current = header; + + if (header == NULL) { diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11721-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11721-01.patch new file mode 100644 index 0000000000..77579de2d2 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11721-01.patch @@ -0,0 +1,43 @@ +From: Mark Andrews +Date: Tue, 14 Apr 2026 15:14:06 +1000 +Subject: Don't sign out of zone records in dnssec-signzone + +dnssec-signzone was signing extraneous records that were not within +the namespace of the zone. This no longer occurs. + +(cherry picked from commit e45c9af7051421fd370f20ba8325199c606223fd) + +Don't sign out of zone records in dnssec-signzone + +dnssec-signzone was signing extraneous records that were not within +the namespace of the zone. This no longer occurs. + +(cherry picked from commit e45c9af7051421fd370f20ba8325199c606223fd) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/1a4986e2533f87e80eb21da3f06708d335aff1e2 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11721 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11721 + +CVE: CVE-2026-11721 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/1a4986e2533f87e80eb21da3f06708d335aff1e2] +Signed-off-by: Hitendra Prajapati +--- + bin/dnssec/dnssec-signzone.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c +index 73855e6..9e3a48a 100644 +--- a/bin/dnssec/dnssec-signzone.c ++++ b/bin/dnssec/dnssec-signzone.c +@@ -1643,6 +1643,11 @@ assignwork(isc_task_t *task, isc_task_t *worker) { + dns_db_detachnode(gdb, &node); + goto next; + } ++ if (!dns_name_issubdomain(name, gorigin)) { ++ dumpnode(name, node); ++ dns_db_detachnode(gdb, &node); ++ goto next; ++ } + /* + * Sort the zone data from the glue and out-of-zone data. + * For NSEC zones nodes with zone data have NSEC records. diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11721-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11721-02.patch new file mode 100644 index 0000000000..125ecf468b --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11721-02.patch @@ -0,0 +1,238 @@ +From: Mark Andrews +Date: Tue, 14 Apr 2026 12:24:33 +1000 +Subject: Invalid signed wildcard records were being accepted + +An RRSIG whose Labels field indicates fewer labels than its signer +name requires was being accepted. When such a record covers a +wildcard, the validator reconstructs a wildcard owner name above the +signer's zone and caches it as secure. RFC 8198 cache synthesis +(synth-from-dnssec) then serves that forged wildcard for unrelated +names, poisoning the cache. + +These records are now rejected, both when an RRSIG is parsed and when +its signature is verified. + +(cherry picked from commit 084ca5ee10515e461d46b63df9660b8394bc7de9) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/15089066b15f826d7487c3d160b5872820f84b83 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11721 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11721 + +CVE: CVE-2026-11721 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/15089066b15f826d7487c3d160b5872820f84b83] +Signed-off-by: Hitendra Prajapati +--- + lib/dns/dnssec.c | 43 +++++++++++++++++++++++++++++----------- + lib/dns/rdata/generic/rrsig_46.c | 37 +++++++++++++++++++++++++--------- + 2 files changed, 59 insertions(+), 21 deletions(-) + +diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c +index 1725de3..9b9b1f2 100644 +--- a/lib/dns/dnssec.c ++++ b/lib/dns/dnssec.c +@@ -130,11 +130,11 @@ dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata, + isc_buffer_t b; + isc_region_t r; + +- INSIST(name != NULL); +- INSIST(rdata != NULL); +- INSIST(mctx != NULL); +- INSIST(key != NULL); +- INSIST(*key == NULL); ++ REQUIRE(name != NULL); ++ REQUIRE(rdata != NULL); ++ REQUIRE(mctx != NULL); ++ REQUIRE(key != NULL); ++ REQUIRE(*key == NULL); + REQUIRE(rdata->type == dns_rdatatype_key || + rdata->type == dns_rdatatype_dnskey); + +@@ -187,12 +187,14 @@ dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + isc_result_t ret; + isc_buffer_t *databuf = NULL; + char data[256 + 8]; ++ unsigned int labels; + unsigned int sigsize; + dns_fixedname_t fnewname; + dns_fixedname_t fsigner; + + REQUIRE(name != NULL); +- REQUIRE(dns_name_countlabels(name) <= 255); ++ labels = dns_name_countlabels(name); ++ REQUIRE(labels <= 255 && labels > 0); + REQUIRE(set != NULL); + REQUIRE(key != NULL); + REQUIRE(inception != NULL); +@@ -221,7 +223,7 @@ dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + + sig.covered = set->type; + sig.algorithm = dst_key_alg(key); +- sig.labels = dns_name_countlabels(name) - 1; ++ sig.labels = labels - 1; + if (dns_name_iswildcard(name)) { + sig.labels--; + } +@@ -365,10 +367,13 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + isc_result_t ret; + unsigned char data[300]; + dst_context_t *ctx = NULL; +- int labels = 0; ++ unsigned int labels; ++ unsigned int siglabels; + bool downcase = false; + + REQUIRE(name != NULL); ++ labels = dns_name_countlabels(name); ++ REQUIRE(labels > 0); + REQUIRE(set != NULL); + REQUIRE(key != NULL); + REQUIRE(mctx != NULL); +@@ -383,6 +388,21 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + return DNS_R_SIGINVALID; + } + ++ /* ++ * The RRSIG labels field can't indicate fewer labels than the ++ * signer. Also the labels shouldn't be greater than that of ++ * the owner name. ++ * ++ * sig.labels doesn't include the root label, so add 1 to account ++ * for it. ++ */ ++ siglabels = sig.labels + 1; ++ if (siglabels < dns_name_countlabels(&sig.signer) || siglabels > labels) ++ { ++ inc_stat(dns_dnssecstats_fail); ++ return DNS_R_SIGINVALID; ++ } ++ + if (isc_serial_lt(sig.timeexpire, sig.timesigned)) { + inc_stat(dns_dnssecstats_fail); + return DNS_R_SIGINVALID; +@@ -464,10 +484,9 @@ again: + * If the name is an expanded wildcard, use the wildcard name. + */ + dns_fixedname_init(&fnewname); +- labels = dns_name_countlabels(name) - 1; + RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), + NULL) == ISC_R_SUCCESS); +- if (labels - sig.labels > 0) { ++ if (labels > siglabels) { + dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1, + NULL, dns_fixedname_name(&fnewname)); + } +@@ -478,7 +497,7 @@ again: + * Create an envelope for each rdata: . + */ + isc_buffer_init(&envbuf, data, sizeof(data)); +- if (labels - sig.labels > 0) { ++ if (labels > siglabels) { + isc_buffer_putuint8(&envbuf, 1); + isc_buffer_putuint8(&envbuf, '*'); + memmove(data + 2, r.base, r.length); +@@ -574,7 +593,7 @@ cleanup_struct: + inc_stat(dns_dnssecstats_fail); + } + +- if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) { ++ if (ret == ISC_R_SUCCESS && labels > siglabels) { + if (wild != NULL) { + RUNTIME_CHECK(dns_name_concatenate( + dns_wildcardname, +diff --git a/lib/dns/rdata/generic/rrsig_46.c b/lib/dns/rdata/generic/rrsig_46.c +index 10bc039..4cf4259 100644 +--- a/lib/dns/rdata/generic/rrsig_46.c ++++ b/lib/dns/rdata/generic/rrsig_46.c +@@ -23,12 +23,12 @@ + static isc_result_t + fromtext_rrsig(ARGS_FROMTEXT) { + isc_token_t token; +- unsigned char c; ++ unsigned char alg, labels; + long i; + dns_rdatatype_t covered; +- char *e; ++ char *e = NULL; + isc_result_t result; +- dns_name_t name; ++ dns_name_t signer; + isc_buffer_t buffer; + uint32_t time_signed, time_expire; + +@@ -61,8 +61,8 @@ fromtext_rrsig(ARGS_FROMTEXT) { + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + false)); +- RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion)); +- RETERR(mem_tobuffer(target, &c, 1)); ++ RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion)); ++ RETERR(mem_tobuffer(target, &alg, 1)); + + /* + * Labels. +@@ -72,8 +72,8 @@ fromtext_rrsig(ARGS_FROMTEXT) { + if (token.value.as_ulong > 0xffU) { + RETTOK(ISC_R_RANGE); + } +- c = (unsigned char)token.value.as_ulong; +- RETERR(mem_tobuffer(target, &c, 1)); ++ labels = (unsigned char)token.value.as_ulong; ++ RETERR(mem_tobuffer(target, &labels, 1)); + + /* + * Original ttl. +@@ -144,12 +144,20 @@ fromtext_rrsig(ARGS_FROMTEXT) { + */ + RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, + false)); +- dns_name_init(&name, NULL); ++ dns_name_init(&signer, NULL); + buffer_fromregion(&buffer, &token.value.as_region); + if (origin == NULL) { + origin = dns_rootname; + } +- RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); ++ RETTOK(dns_name_fromtext(&signer, &buffer, origin, options, target)); ++ ++ /* ++ * (RRSIG labels doesn't include the root label, so add one ++ * to normalize it before checking against the signer.) ++ */ ++ if ((unsigned int)(labels + 1) < dns_name_countlabels(&signer)) { ++ RETTOK(ISC_R_RANGE); ++ } + + /* + * Sig. +@@ -278,6 +286,7 @@ static isc_result_t + fromwire_rrsig(ARGS_FROMWIRE) { + isc_region_t sr; + dns_name_t name; ++ unsigned char labels; + + REQUIRE(type == dns_rdatatype_rrsig); + +@@ -300,6 +309,8 @@ fromwire_rrsig(ARGS_FROMWIRE) { + return ISC_R_UNEXPECTEDEND; + } + ++ labels = sr.base[3]; ++ + isc_buffer_forward(source, 18); + RETERR(mem_tobuffer(target, sr.base, 18)); + +@@ -309,6 +320,14 @@ fromwire_rrsig(ARGS_FROMWIRE) { + dns_name_init(&name, NULL); + RETERR(dns_name_fromwire(&name, source, dctx, options, target)); + ++ /* ++ * (RRSIG labels doesn't include the root label, so add one ++ * to normalize it before checking against the signer.) ++ */ ++ if ((unsigned int)(labels + 1) < dns_name_countlabels(&name)) { ++ RETERR(DNS_R_FORMERR); ++ } ++ + /* + * Sig. + */ diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-11721-03.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-11721-03.patch new file mode 100644 index 0000000000..63fae84da1 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-11721-03.patch @@ -0,0 +1,147 @@ +From: Mark Andrews +Date: Tue, 14 Apr 2026 13:46:22 +1000 +Subject: Test RRSIG record parsing + +In particular test that labels and signer fields are consistent. + +(cherry picked from commit 5a95e64731afe63d348d272cc4d3b2f9847150c2) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/19e496ca260b6a756ae1378e8ebcbdb666b7d9ed +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-11721 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-11721 + +CVE: CVE-2026-11721 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/19e496ca260b6a756ae1378e8ebcbdb666b7d9ed] +Signed-off-by: Hitendra Prajapati +--- + tests/dns/rdata_test.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 110 insertions(+) + +diff --git a/tests/dns/rdata_test.c b/tests/dns/rdata_test.c +index 7f0df6e..c704d98 100644 +--- a/tests/dns/rdata_test.c ++++ b/tests/dns/rdata_test.c +@@ -2504,6 +2504,115 @@ ISC_RUN_TEST_IMPL(rkey) { + dns_rdatatype_rkey, sizeof(dns_rdata_rkey_t)); + } + ++ISC_RUN_TEST_IMPL(rrsig) { ++ text_ok_t text_ok[] = { ++ TEXT_VALID("SOA 8 0 86400 20260426170000 20260413160000 54393 " ++ ". " ++ "tFbcoVP8MnpecUquJ/aj+XeNgV7ts9GSHVkXaXRJrJ/" ++ "TEkOZApVG0F6E " ++ "9sYpxGk2ItweLL43ujioGj0HWwZDRR+vbur+O/" ++ "dIdheiig1VvU+9HXLi " ++ "QOViY9Kc64ixdyJhYCC5K+bO1qsHxd+" ++ "KJXOaxyHbqchYkDFy4PL6qftE " ++ "VaLkueRgjXgOsq/" ++ "NxvCXDgAa5xy0+3Sl0myxIs8rJ5KeXfJQFe7qxgaw " ++ "VjJsJTKw8neOTw2rQfLaigWu2LIWw+" ++ "IyVrLjZJdLqGkiLBGd1w4X3U12 " ++ "fFxoY3eqzNgBEtduoGKPZ/" ++ "NpP9cuKJORJ18283aV8hR4WO91VR0q1zcM jLwqUg=="), ++ /* labels too short for signer */ ++ TEXT_INVALID("SOA 8 0 86400 20260426170000 20260413160000 " ++ "54393 example. " ++ "tFbcoVP8MnpecUquJ/aj+XeNgV7ts9GSHVkXaXRJrJ/" ++ "TEkOZApVG0F6E " ++ "9sYpxGk2ItweLL43ujioGj0HWwZDRR+vbur+O/" ++ "dIdheiig1VvU+9HXLi " ++ "QOViY9Kc64ixdyJhYCC5K+bO1qsHxd+" ++ "KJXOaxyHbqchYkDFy4PL6qftE " ++ "VaLkueRgjXgOsq/" ++ "NxvCXDgAa5xy0+3Sl0myxIs8rJ5KeXfJQFe7qxgaw " ++ "VjJsJTKw8neOTw2rQfLaigWu2LIWw+" ++ "IyVrLjZJdLqGkiLBGd1w4X3U12 " ++ "fFxoY3eqzNgBEtduoGKPZ/" ++ "NpP9cuKJORJ18283aV8hR4WO91VR0q1zcM jLwqUg=="), ++ /* ++ * Sentinel. ++ */ ++ TEXT_SENTINEL() ++ }; ++ wire_ok_t wire_ok[] = { ++ WIRE_VALID(0x00, 0x06, 0x08, 0x00, 0x00, 0x01, 0x51, 0x80, 0x69, ++ 0xee, 0x44, 0x90, 0x69, 0xdd, 0x13, 0x00, 0xd4, 0x79, ++ 0x00, 0xb4, 0x56, 0xdc, 0xa1, 0x53, 0xfc, 0x32, 0x7a, ++ 0x5e, 0x71, 0x4a, 0xae, 0x27, 0xf6, 0xa3, 0xf9, 0x77, ++ 0x8d, 0x81, 0x5e, 0xed, 0xb3, 0xd1, 0x92, 0x1d, 0x59, ++ 0x17, 0x69, 0x74, 0x49, 0xac, 0x9f, 0xd3, 0x12, 0x43, ++ 0x99, 0x02, 0x95, 0x46, 0xd0, 0x5e, 0x84, 0xf6, 0xc6, ++ 0x29, 0xc4, 0x69, 0x36, 0x22, 0xdc, 0x1e, 0x2c, 0xbe, ++ 0x37, 0xba, 0x38, 0xa8, 0x1a, 0x3d, 0x07, 0x5b, 0x06, ++ 0x43, 0x45, 0x1f, 0xaf, 0x6e, 0xea, 0xfe, 0x3b, 0xf7, ++ 0x48, 0x76, 0x17, 0xa2, 0x8a, 0x0d, 0x55, 0xbd, 0x4f, ++ 0xbd, 0x1d, 0x72, 0xe2, 0x40, 0xe5, 0x62, 0x63, 0xd2, ++ 0x9c, 0xeb, 0x88, 0xb1, 0x77, 0x22, 0x61, 0x60, 0x20, ++ 0xb9, 0x2b, 0xe6, 0xce, 0xd6, 0xab, 0x07, 0xc5, 0xdf, ++ 0x8a, 0x25, 0x73, 0x9a, 0xc7, 0x21, 0xdb, 0xa9, 0xc8, ++ 0x58, 0x90, 0x31, 0x72, 0xe0, 0xf2, 0xfa, 0xa9, 0xfb, ++ 0x44, 0x55, 0xa2, 0xe4, 0xb9, 0xe4, 0x60, 0x8d, 0x78, ++ 0x0e, 0xb2, 0xaf, 0xcd, 0xc6, 0xf0, 0x97, 0x0e, 0x00, ++ 0x1a, 0xe7, 0x1c, 0xb4, 0xfb, 0x74, 0xa5, 0xd2, 0x6c, ++ 0xb1, 0x22, 0xcf, 0x2b, 0x27, 0x92, 0x9e, 0x5d, 0xf2, ++ 0x50, 0x15, 0xee, 0xea, 0xc6, 0x06, 0xb0, 0x56, 0x32, ++ 0x6c, 0x25, 0x32, 0xb0, 0xf2, 0x77, 0x8e, 0x4f, 0x0d, ++ 0xab, 0x41, 0xf2, 0xda, 0x8a, 0x05, 0xae, 0xd8, 0xb2, ++ 0x16, 0xc3, 0xe2, 0x32, 0x56, 0xb2, 0xe3, 0x64, 0x97, ++ 0x4b, 0xa8, 0x69, 0x22, 0x2c, 0x11, 0x9d, 0xd7, 0x0e, ++ 0x17, 0xdd, 0x4d, 0x76, 0x7c, 0x5c, 0x68, 0x63, 0x77, ++ 0xaa, 0xcc, 0xd8, 0x01, 0x12, 0xd7, 0x6e, 0xa0, 0x62, ++ 0x8f, 0x67, 0xf3, 0x69, 0x3f, 0xd7, 0x2e, 0x28, 0x93, ++ 0x91, 0x27, 0x5f, 0x36, 0xf3, 0x76, 0x95, 0xf2, 0x14, ++ 0x78, 0x58, 0xef, 0x75, 0x55, 0x1d, 0x2a, 0xd7, 0x37, ++ 0x0c, 0x8c, 0xbc, 0x2a, 0x52), ++ /* labels too short for signer */ ++ WIRE_INVALID( ++ 0x00, 0x06, 0x08, 0x00, 0x00, 0x01, 0x51, 0x80, 0x69, ++ 0xee, 0x44, 0x90, 0x69, 0xdd, 0x13, 0x00, 0xd4, 0x79, ++ 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x00, ++ 0xb4, 0x56, 0xdc, 0xa1, 0x53, 0xfc, 0x32, 0x7a, 0x5e, ++ 0x71, 0x4a, 0xae, 0x27, 0xf6, 0xa3, 0xf9, 0x77, 0x8d, ++ 0x81, 0x5e, 0xed, 0xb3, 0xd1, 0x92, 0x1d, 0x59, 0x17, ++ 0x69, 0x74, 0x49, 0xac, 0x9f, 0xd3, 0x12, 0x43, 0x99, ++ 0x02, 0x95, 0x46, 0xd0, 0x5e, 0x84, 0xf6, 0xc6, 0x29, ++ 0xc4, 0x69, 0x36, 0x22, 0xdc, 0x1e, 0x2c, 0xbe, 0x37, ++ 0xba, 0x38, 0xa8, 0x1a, 0x3d, 0x07, 0x5b, 0x06, 0x43, ++ 0x45, 0x1f, 0xaf, 0x6e, 0xea, 0xfe, 0x3b, 0xf7, 0x48, ++ 0x76, 0x17, 0xa2, 0x8a, 0x0d, 0x55, 0xbd, 0x4f, 0xbd, ++ 0x1d, 0x72, 0xe2, 0x40, 0xe5, 0x62, 0x63, 0xd2, 0x9c, ++ 0xeb, 0x88, 0xb1, 0x77, 0x22, 0x61, 0x60, 0x20, 0xb9, ++ 0x2b, 0xe6, 0xce, 0xd6, 0xab, 0x07, 0xc5, 0xdf, 0x8a, ++ 0x25, 0x73, 0x9a, 0xc7, 0x21, 0xdb, 0xa9, 0xc8, 0x58, ++ 0x90, 0x31, 0x72, 0xe0, 0xf2, 0xfa, 0xa9, 0xfb, 0x44, ++ 0x55, 0xa2, 0xe4, 0xb9, 0xe4, 0x60, 0x8d, 0x78, 0x0e, ++ 0xb2, 0xaf, 0xcd, 0xc6, 0xf0, 0x97, 0x0e, 0x00, 0x1a, ++ 0xe7, 0x1c, 0xb4, 0xfb, 0x74, 0xa5, 0xd2, 0x6c, 0xb1, ++ 0x22, 0xcf, 0x2b, 0x27, 0x92, 0x9e, 0x5d, 0xf2, 0x50, ++ 0x15, 0xee, 0xea, 0xc6, 0x06, 0xb0, 0x56, 0x32, 0x6c, ++ 0x25, 0x32, 0xb0, 0xf2, 0x77, 0x8e, 0x4f, 0x0d, 0xab, ++ 0x41, 0xf2, 0xda, 0x8a, 0x05, 0xae, 0xd8, 0xb2, 0x16, ++ 0xc3, 0xe2, 0x32, 0x56, 0xb2, 0xe3, 0x64, 0x97, 0x4b, ++ 0xa8, 0x69, 0x22, 0x2c, 0x11, 0x9d, 0xd7, 0x0e, 0x17, ++ 0xdd, 0x4d, 0x76, 0x7c, 0x5c, 0x68, 0x63, 0x77, 0xaa, ++ 0xcc, 0xd8, 0x01, 0x12, 0xd7, 0x6e, 0xa0, 0x62, 0x8f, ++ 0x67, 0xf3, 0x69, 0x3f, 0xd7, 0x2e, 0x28, 0x93, 0x91, ++ 0x27, 0x5f, 0x36, 0xf3, 0x76, 0x95, 0xf2, 0x14, 0x78, ++ 0x58, 0xef, 0x75, 0x55, 0x1d, 0x2a, 0xd7, 0x37, 0x0c, ++ 0x8c, 0xbc, 0x2a, 0x52), ++ ++ WIRE_SENTINEL() ++ }; ++ check_rdata(text_ok, wire_ok, NULL, false, dns_rdataclass_in, ++ dns_rdatatype_rrsig, sizeof(dns_rdata_rrsig_t)); ++} ++ + ISC_RUN_TEST_IMPL(resinfo) { + text_ok_t text_ok[] = { + TEXT_VALID_CHANGED("qnamemin exterr=15,16,17 " +@@ -3357,6 +3466,7 @@ ISC_TEST_ENTRY(nsec3) + ISC_TEST_ENTRY(nxt) + ISC_TEST_ENTRY(resinfo) + ISC_TEST_ENTRY(rkey) ++ISC_TEST_ENTRY(rrsig) + ISC_TEST_ENTRY(sshfp) + ISC_TEST_ENTRY(wallet) + ISC_TEST_ENTRY(wks) diff --git a/meta/recipes-connectivity/bind/bind_9.18.49.bb b/meta/recipes-connectivity/bind/bind_9.18.49.bb index dc274f6076..8218772531 100644 --- a/meta/recipes-connectivity/bind/bind_9.18.49.bb +++ b/meta/recipes-connectivity/bind/bind_9.18.49.bb @@ -29,6 +29,10 @@ SRC_URI = "https://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.xz \ file://CVE-2026-11331-01.patch \ file://CVE-2026-11331-02.patch \ file://CVE-2026-11331-03.patch \ + file://CVE-2026-11622.patch \ + file://CVE-2026-11721-01.patch \ + file://CVE-2026-11721-02.patch \ + file://CVE-2026-11721-03.patch \ " SRC_URI[sha256sum] = "c43ce4548ebed788cd9df63658a7de105ceafba43fcd63fa352b1093e525cd24" From patchwork Mon Sep 28 07:11:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 99452 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A04ABC9832F for ; Mon, 28 Sep 2026 07:13:50 +0000 (UTC) Received: from mail-dy2-f43.google.com (mail-dy2-f43.google.com [74.125.229.43]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.51995.1790579623301999316 for ; Mon, 28 Sep 2026 00:13:43 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=Nkk6s7Lr; spf=pass (domain: mvista.com, ip: 74.125.229.43, mailfrom: hprajapati@mvista.com) Received: by mail-dy2-f43.google.com with SMTP id 5a478bee46e88-340f56c44b0so937470eec.1 for ; Mon, 28 Sep 2026 00:13:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1790579623; x=1791184423; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=E5kVV7WqFnJMxYlVc8f8NiZBfdtwJuff9S0G2pjJVU8=; b=Nkk6s7Lrg6/coUUowCTfA1Swbuwiz+MX5Kbx9sEif7/d9GXbvA1r0MxhYLHWV1fFq0 Mtv/pu0DLK4ROUsXKbmjS5wR6mcwY2gO2ssHSp3SZD0Fst1ZRVNwj5PgT3ozs09JqaE4 +bx8HZfUPy2yeq4IL/ZcycVAQYaTnV9U+qTvM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790579623; x=1791184423; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=E5kVV7WqFnJMxYlVc8f8NiZBfdtwJuff9S0G2pjJVU8=; b=MDS6wrYcuxMhdpJkpCZalMCKNtfCz+Rx3ZpbohcjN75VH1EUuh7aEfl0s1TB6tPY/M BW1pWHKSasuVw8258AP94w1HGmjYkRVBghb1xX8a5Z3t/ybHJuH10UXsKIJpLmLUuurw n0HHJY3xPL6nRkrDRSHGruwGgvyyMUaCPTnfww1vlgTm5mVP2UCKbs8r379CufZkm2NM xLs5XpdsQ1ar4PgCTJJaslTc3mrczp9BTQr8ck1NRUtXhwxaXRi1/BSEWBT3h/Z8LcRO R2OJ0+iZ5Ae2q38jMEpc5JxcD++3ToazQwSGu5HZfbox1159OXGTgDVW6vlSuPlakdIv 1drg== X-Gm-Message-State: AFq9FYKlh0AVJdhD99bcDSMAAmB6SVlsrOambuYfg6kNO6XMe+3BAD8o VHPHWPpg94plSBWQz17JkgmHatMUFC2lrC9hAps3glJfVhWYdoP2aaboRlEi+DfCw5CxdG3qEnE P0fQZaDk= X-Gm-Gg: AYBFou1GAJ53CfTe06ZbO/CRaJ1DGKxoyXn1G+JDtxGC3yF3wlQxE4Ym4kouvLO/8vS M3Mm1Zt6l8NBSiEbDzrqNH7L9ss10NQxscmUk/ETwrANDjVKW6m+NvEwYRs/11c+bHd8lX182Wk SzreYaDaXnIyh8ZMB41HDq3evNDed/QBq2iUco56isKekhZ5CmBNjC7TIeFpphdtsUG1xzPATlS /DePxZS4qT2jT9C6Di8LnnXauUjuU4/TaYVDc59WlY2phUgVj+K3XqaOLSqJ9RcumMgXuBTCMJ3 azOt+XnTz4yP8fft0JOOSl1tfVUIBHMtXs1YHt0/wqtn+P5/kN+xKhSFWNl00eTS5FgsMge3tD+ DKpYbGINBaKxNquEMuPR9mSJW8HUCQU92pI8MPgjbcJLR6Tpc2Pzl0RldQt9vccdivEJR7/EVVo 6dTDCxt6rd41RUx83KGDk27w/2CSEo/TitiyW0Au/a4uj6LFomf+KS2urT7fC5brHsz32wGPANO YJgtwXVkHI= X-Received: by 2002:a05:7300:640e:b0:33b:ebaa:e03b with SMTP id 5a478bee46e88-34271d8d7b6mr11104716eec.22.1790579622234; Mon, 28 Sep 2026 00:13:42 -0700 (PDT) Received: from MVIN00013.mvista.com ([150.129.170.212]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3434958c3adsm31166948eec.22.2026.09.28.00.13.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2026 00:13:41 -0700 (PDT) From: Hitendra Prajapati To: openembedded-core@lists.openembedded.org Cc: Hitendra Prajapati Subject: [scarthgap][PATCH 5/6] bind: fix for CVE-2026-12617 Date: Mon, 28 Sep 2026 12:41:10 +0530 Message-ID: <20260928071115.304055-5-hprajapati@mvista.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260928071115.304055-1-hprajapati@mvista.com> References: <20260928071115.304055-1-hprajapati@mvista.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 07:13:50 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/246735 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 --- .../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 diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-12617-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-12617-01.patch new file mode 100644 index 0000000000..35d357374b --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-12617-01.patch @@ -0,0 +1,283 @@ +From: Colin Vidal +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 +--- + 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; diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-12617-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-12617-02.patch new file mode 100644 index 0000000000..7dfaafb80d --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-12617-02.patch @@ -0,0 +1,292 @@ +From: Colin Vidal +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 +--- + 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") diff --git a/meta/recipes-connectivity/bind/bind_9.18.49.bb b/meta/recipes-connectivity/bind/bind_9.18.49.bb index 8218772531..b048ba6559 100644 --- a/meta/recipes-connectivity/bind/bind_9.18.49.bb +++ b/meta/recipes-connectivity/bind/bind_9.18.49.bb @@ -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" From patchwork Mon Sep 28 07:11:11 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 99453 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A551DC9832F for ; Mon, 28 Sep 2026 07:14:30 +0000 (UTC) Received: from mail-dy2-f41.google.com (mail-dy2-f41.google.com [74.125.229.41]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.52005.1790579669961690059 for ; Mon, 28 Sep 2026 00:14:30 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=GKAw9KEs; spf=pass (domain: mvista.com, ip: 74.125.229.41, mailfrom: hprajapati@mvista.com) Received: by mail-dy2-f41.google.com with SMTP id 5a478bee46e88-347327e3aeaso788593eec.3 for ; Mon, 28 Sep 2026 00:14:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; t=1790579669; x=1791184469; darn=lists.openembedded.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=0J39Kusxd68apSrQ3Mxq6OJ9zq0v4z7nqnwKG9JKfF4=; b=GKAw9KEsVnOuWYTriPT6S1zgJ9pn051JfTi9Na+cq5U6SZb3OsBITuAbPlzmIRF54S o7xTKikKTUm0vBt/skd4sGH99+hMzPaaehc7z+ZzX4z0OW1v+d5ISQpDa+MR+7yOali7 ho6mZuBCZt4YVZEvF7dj7Cnu8xSMI5skmVTyw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790579669; x=1791184469; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=0J39Kusxd68apSrQ3Mxq6OJ9zq0v4z7nqnwKG9JKfF4=; b=SSF/NQxUlm1uNyo0A50cBO6ET8x9JTz8cN2r4K3RRTpQgqujLjTHGPCfw4I/YxBtQz gdHP69GSXeyYTeAbRNOm61bR7um1v78ubt9M5kzgm7Z/ik1KkgJxXlBvajUD7VMyGYo3 oWeUB1IGQ1jbwG63yK7Jt7KL3MzelyJjOtkHu6TuUOGqK6QlI09oe2kJRDp47dQjRtT2 TSXU/b/m3bPMBBTeNhq90fIptOIu4AC6PK4khIvzl4fwE2ITOzZ2sZA7bRhB8x410bMO 3DB3Ci4ay/jG0TSGZP1iAFYSfXf4DPI0LPbme1xIMa2kDqx9yecZEoZlKluW/ICsUwae wN9g== X-Gm-Message-State: AFq9FYJNszvb/T8fQWprG0kWx0GaI27Ic5b9HORL2iPnST00g5VhIbkF x6I+sAnfIFZlP4ogLISl9uJ7Mf+TaPkxg7unqZt0pGvig8/YcjSKXjBcakcsJZlYC3shx3hom6V duwNngF0= X-Gm-Gg: AYBFou3/5APEcYlg3G1+GsDAxLUQ1IS2cgEfynQs0UohM0Lh2K5ebC3yIblXq56TEXN 7GGjAJChlVOtBZ6JkdaffmfsFiBTxYUYrHdEw2r1rruwb2rQgqFpNykObvSEzW3clTEIcxSJX1E gWTOpfRIestr3tQnbG+LQvhOOjREsmGG5PwNeDUh1hGJkWozgC67ZHXvxrjGVj7xOY72kZTHobl KUOrAEDETGfkTu6Zd+aJL1icw+H2tdAT2i//Dp9c9vbxEsez0HWloCNTDX9KJDYIvd9VcIzjvHw zBgD6jzHzj4b+KrooKsK1yz8VR60a2m7y/jQr/RnpjkcbVbDIccjoCKr6U8SeYroYzlwcvv3uag Jc7dxKpbLmptjHN1jBdAuo85ayO5ONaCPmItkdYHMDxZPx3set+1un8wD7szs6eVjAO9HxEC2tk z4Wzfq1ZbAuNg4Lr4N98KyLLnb35GNX9D2pCpDDZaW6quBzSKJRJi9XPtdDSrO1N6gJgPSiGTr3 dG2Ab3xOS4= X-Received: by 2002:a05:7301:152a:b0:339:7c91:21f4 with SMTP id 5a478bee46e88-34273252770mr9956217eec.34.1790579668372; Mon, 28 Sep 2026 00:14:28 -0700 (PDT) Received: from MVIN00013.mvista.com ([150.129.170.212]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3434958c3adsm31166948eec.22.2026.09.28.00.13.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Sep 2026 00:14:27 -0700 (PDT) From: Hitendra Prajapati To: openembedded-core@lists.openembedded.org Cc: Hitendra Prajapati Subject: [scarthgap][PATCH 6/6] bind: fix for CVE-2026-13204, CVE-2026-13321 Date: Mon, 28 Sep 2026 12:41:11 +0530 Message-ID: <20260928071115.304055-6-hprajapati@mvista.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260928071115.304055-1-hprajapati@mvista.com> References: <20260928071115.304055-1-hprajapati@mvista.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 28 Sep 2026 07:14:30 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/246736 Pick patch from [1,2,3] & [4,5,6] also mentioned at Debian report in [7] & [8] [1] https://gitlab.isc.org/isc-projects/bind9/-/commit/0cf010c153518f1f9831e201891ecba8d8ba65e1 [2] https://gitlab.isc.org/isc-projects/bind9/-/commit/6c0e599ea85c0c53a4af09742e64e193da089bb4 [3] https://gitlab.isc.org/isc-projects/bind9/-/commit/48f5aa5fb3746d6194edcc57e8792a8b3cc3b454 [4] https://gitlab.isc.org/isc-projects/bind9/-/commit/c969ad2c17b43dd999e358bfeb280d3df6fab822 [5] https://gitlab.isc.org/isc-projects/bind9/-/commit/058023c66f11d78590d4aa8c4f98946c4c965e21 [6] https://gitlab.isc.org/isc-projects/bind9/-/commit/f751e19a30d107f04c2f644aff9f8dab8fed03ab [7] https://security-tracker.debian.org/tracker/CVE-2026-13204 [8] https://security-tracker.debian.org/tracker/CVE-2026-13321 Signed-off-by: Hitendra Prajapati --- .../bind/bind/CVE-2026-13204-01.patch | 395 +++++++++++++++++ .../bind/bind/CVE-2026-13204-02.patch | 215 ++++++++++ .../bind/bind/CVE-2026-13204-03.patch | 161 +++++++ .../bind/bind/CVE-2026-13321-01.patch | 401 ++++++++++++++++++ .../bind/bind/CVE-2026-13321-02.patch | 88 ++++ .../bind/bind/CVE-2026-13321-03.patch | 203 +++++++++ .../recipes-connectivity/bind/bind_9.18.49.bb | 6 + 7 files changed, 1469 insertions(+) create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-13204-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-13204-02.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-13204-03.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-13321-01.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-13321-02.patch create mode 100644 meta/recipes-connectivity/bind/bind/CVE-2026-13321-03.patch diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-13204-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-13204-01.patch new file mode 100644 index 0000000000..4b2bebfcc3 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-13204-01.patch @@ -0,0 +1,395 @@ +From: Alessio Podda +Date: Fri, 12 Jun 2026 11:16:01 +0200 +Subject: Reproducer for #5985 addnoqname mismatch + +LLM generated. + +(cherry picked from commit 5f4de929b3e4749b6e32c51660be11c47c2514e6) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/0cf010c153518f1f9831e201891ecba8d8ba65e1 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-13204 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-13204 + +CVE: CVE-2026-13204 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/0cf010c153518f1f9831e201891ecba8d8ba65e1] +Signed-off-by: Hitendra Prajapati +--- + .../ans1/ans.py | 11 ++ + .../ns2/named.conf.j2 | 7 +- + .../repro_5985_findnoqname_runtime_check/server.py | 189 +++++++++++++++++++++ + .../tests_repro_5985_findnoqname_runtime_check.py | 120 +++++++++++++ + 4 files changed, 325 insertions(+), 2 deletions(-) + create mode 100644 bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py + copy bin/tests/system/{nsec3_impersonation => repro_5985_findnoqname_runtime_check}/ns2/named.conf.j2 (77%) + create mode 100644 bin/tests/system/repro_5985_findnoqname_runtime_check/server.py + create mode 100644 bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py + +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py b/bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py +new file mode 100644 +index 0000000..cb01c8a +--- /dev/null ++++ b/bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py +@@ -0,0 +1,11 @@ ++#!/usr/bin/python3 ++ ++# Copyright (C) Internet Systems Consortium, Inc. ("ISC") ++# ++# SPDX-License-Identifier: MPL-2.0 ++ ++from server import main ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 b/bin/tests/system/repro_5985_findnoqname_runtime_check/ns2/named.conf.j2 +similarity index 77% +copy from bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 +copy to bin/tests/system/repro_5985_findnoqname_runtime_check/ns2/named.conf.j2 +index 2c9b0bb..7d6fc84 100644 +--- a/bin/tests/system/nsec3_impersonation/ns2/named.conf.j2 ++++ b/bin/tests/system/repro_5985_findnoqname_runtime_check/ns2/named.conf.j2 +@@ -10,6 +10,9 @@ options { + listen-on-v6 { none; }; + recursion yes; + dnssec-validation yes; ++ trust-anchor-telemetry no; ++ resolver-query-timeout 5000; ++ qname-minimization off; + }; + + controls { +@@ -23,11 +26,11 @@ zone "." { + file "../../_common/root.hint"; + }; + +-zone "tld.test" { ++zone "f217.test" { + type static-stub; + server-addresses { 10.53.0.1; }; + }; + + trust-anchors { +- tld.test. static-key 257 3 13 "@TLD_DNSKEY@"; ++ f217.test. static-key 257 3 13 "@ZONE_DNSKEY@"; + }; +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/server.py b/bin/tests/system/repro_5985_findnoqname_runtime_check/server.py +new file mode 100644 +index 0000000..18d0ac1 +--- /dev/null ++++ b/bin/tests/system/repro_5985_findnoqname_runtime_check/server.py +@@ -0,0 +1,189 @@ ++#!/usr/bin/python3 ++ ++# Copyright (C) Internet Systems Consortium, Inc. ("ISC") ++# ++# SPDX-License-Identifier: MPL-2.0 ++ ++from collections.abc import AsyncGenerator ++from dataclasses import dataclass ++from datetime import datetime, timedelta, timezone ++from pathlib import Path ++ ++import base64 ++import json ++ ++from cryptography.hazmat.primitives import serialization ++ ++import dns.dnssec ++import dns.flags ++import dns.message ++import dns.name ++import dns.rdata ++import dns.rdataclass ++import dns.rcode ++import dns.rdatatype ++import dns.rrset ++ ++from isctest.asyncserver import ( ++ AsyncDnsServer, ++ DnsResponseSend, ++ QueryContext, ++ ResponseHandler, ++) ++ ++TTL = 300 ++ZONE = "f217.test." ++CHILD = f"evil.{ZONE}" ++ATTACK = f"www.{CHILD}" ++NSEC_OWNER = f"00000000.{CHILD}" ++NSEC_NEXT = f"zzz.{CHILD}" ++FORGED_A = "192.0.2.217" ++ ++ ++@dataclass(frozen=True) ++class Key: ++ zone: dns.name.Name ++ private_key: object ++ dnskey: dns.rdata.Rdata ++ ++ ++def name(text: str) -> dns.name.Name: ++ return dns.name.from_text(text) ++ ++ ++def load_key() -> Key: ++ path = Path(__file__).resolve().parent / "keys.json" ++ with path.open(encoding="utf-8") as keys_file: ++ raw_key = json.load(keys_file)[ZONE] ++ ++ private_key = serialization.load_pem_private_key( ++ raw_key["private_pem"].encode("ascii"), ++ password=None, ++ ) ++ dnskey = dns.rdata.from_text( ++ dns.rdataclass.IN, dns.rdatatype.DNSKEY, raw_key["dnskey"] ++ ) ++ return Key(name(ZONE), private_key, dnskey) ++ ++ ++def rrset( ++ owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str ++) -> dns.rrset.RRset: ++ return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, *rdatas) ++ ++ ++def rrset_from_rdata(owner: str, rdata: dns.rdata.Rdata) -> dns.rrset.RRset: ++ return dns.rrset.from_rdata(name(owner), TTL, rdata) ++ ++ ++def add_signed( ++ section: list[dns.rrset.RRset], covered: dns.rrset.RRset, signer: Key ++) -> None: ++ rrsig = dns.dnssec.sign( ++ covered, ++ signer.private_key, ++ signer.zone, ++ signer.dnskey, ++ lifetime=86400, ++ verify=True, ++ ) ++ section.append(covered) ++ section.append(dns.rrset.from_rdata(covered.name, covered.ttl, rrsig)) ++ ++ ++def soa_rrset(zone: str) -> dns.rrset.RRset: ++ return rrset( ++ zone, ++ dns.rdatatype.SOA, ++ f"ns.{ZONE} hostmaster.{ZONE} 1 7200 3600 1209600 300", ++ ) ++ ++ ++def garbage_rrsig( ++ owner: str, covered: dns.rdatatype.RdataType, labels: int, signer: str ++) -> dns.rrset.RRset: ++ now = datetime.now(timezone.utc) ++ inception = (now - timedelta(hours=1)).strftime("%Y%m%d%H%M%S") ++ expiration = (now + timedelta(days=1)).strftime("%Y%m%d%H%M%S") ++ signature = base64.b64encode(bytes(64)).decode("ascii") ++ text = ( ++ f"{dns.rdatatype.to_text(covered)} 13 {labels} {TTL} " ++ f"{expiration} {inception} 12345 {signer} {signature}" ++ ) ++ rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.RRSIG, text) ++ return dns.rrset.from_rdata(name(owner), TTL, rdata) ++ ++ ++def add_ds_denial(response: dns.message.Message, key: Key) -> None: ++ add_signed(response.authority, soa_rrset(ZONE), key) ++ nsec = rrset(CHILD, dns.rdatatype.NSEC, f"ns.{ZONE} NS RRSIG NSEC") ++ add_signed(response.authority, nsec, key) ++ ++ ++def add_attack_answer(response: dns.message.Message) -> None: ++ response.answer.append(rrset(ATTACK, dns.rdatatype.A, FORGED_A)) ++ response.answer.append(garbage_rrsig(ATTACK, dns.rdatatype.A, 1, CHILD)) ++ ++ nsec = rrset( ++ NSEC_OWNER, ++ dns.rdatatype.NSEC, ++ f"{NSEC_NEXT} A RRSIG NSEC", ++ ) ++ nsec3 = rrset( ++ NSEC_OWNER, ++ dns.rdatatype.NSEC3, ++ "1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG", ++ ) ++ response.authority.append(nsec) ++ response.authority.append( ++ garbage_rrsig( ++ NSEC_OWNER, ++ dns.rdatatype.NSEC, ++ len(name(NSEC_OWNER).labels) - 1, ++ CHILD, ++ ) ++ ) ++ response.authority.append(nsec3) ++ ++ ++class RuntimeCheckHandler(ResponseHandler): ++ def __init__(self, key: Key) -> None: ++ self.key = key ++ self.zone = name(ZONE) ++ self.child = name(CHILD) ++ self.attack = name(ATTACK) ++ ++ def match(self, qctx: QueryContext) -> bool: ++ return qctx.qname.is_subdomain(self.zone) ++ ++ async def get_responses( ++ self, qctx: QueryContext ++ ) -> AsyncGenerator[DnsResponseSend, None]: ++ qctx.prepare_new_response(with_zone_data=False) ++ qctx.response.flags |= dns.flags.AA ++ qctx.response.set_rcode(dns.rcode.NOERROR) ++ ++ if qctx.qname == self.zone and qctx.qtype == dns.rdatatype.DNSKEY: ++ add_signed( ++ qctx.response.answer, ++ rrset_from_rdata(ZONE, self.key.dnskey), ++ self.key, ++ ) ++ elif qctx.qname == self.zone and qctx.qtype == dns.rdatatype.SOA: ++ add_signed(qctx.response.answer, soa_rrset(ZONE), self.key) ++ elif qctx.qname == self.child and qctx.qtype == dns.rdatatype.DS: ++ add_ds_denial(qctx.response, self.key) ++ elif qctx.qname == self.child and qctx.qtype == dns.rdatatype.DNSKEY: ++ qctx.response.authority.append(soa_rrset(CHILD)) ++ elif qctx.qname == self.attack and qctx.qtype == dns.rdatatype.A: ++ add_attack_answer(qctx.response) ++ else: ++ add_signed(qctx.response.authority, soa_rrset(ZONE), self.key) ++ ++ yield DnsResponseSend(qctx.response, authoritative=True) ++ ++ ++def main() -> None: ++ server = AsyncDnsServer(default_aa=True) ++ server.install_response_handlers(RuntimeCheckHandler(load_key())) ++ server.run() +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py b/bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py +new file mode 100644 +index 0000000..0e7d71c +--- /dev/null ++++ b/bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py +@@ -0,0 +1,120 @@ ++#!/usr/bin/python3 ++ ++# Copyright (C) Internet Systems Consortium, Inc. ("ISC") ++# ++# SPDX-License-Identifier: MPL-2.0 ++ ++from pathlib import Path ++ ++import json ++ ++from cryptography.hazmat.primitives import serialization ++from cryptography.hazmat.primitives.asymmetric import ec ++ ++import dns.dnssec ++import dns.name ++import dns.rdataclass ++import dns.rdatatype ++import pytest ++ ++import isctest ++ ++ZONE = "f217.test." ++CHILD = f"evil.{ZONE}" ++ATTACK = f"www.{CHILD}" ++NSEC_OWNER = f"00000000.{CHILD}" ++FORGED_A = "192.0.2.217" ++AUTH = "10.53.0.1" ++RESOLVER = "10.53.0.2" ++ ++pytestmark = pytest.mark.extra_artifacts( ++ [ ++ "ans*/ans.run", ++ "keys.json", ++ ] ++) ++ ++ ++def _make_key(): ++ private_key = ec.generate_private_key(ec.SECP256R1()) ++ dnskey = dns.dnssec.make_dnskey( ++ private_key.public_key(), ++ algorithm="ECDSAP256SHA256", ++ flags=257, ++ ) ++ private_pem = private_key.private_bytes( ++ encoding=serialization.Encoding.PEM, ++ format=serialization.PrivateFormat.PKCS8, ++ encryption_algorithm=serialization.NoEncryption(), ++ ).decode("ascii") ++ return { ++ "private_pem": private_pem, ++ "dnskey": dnskey.to_text(), ++ } ++ ++ ++def bootstrap(): ++ keys = {ZONE: _make_key()} ++ Path("keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") ++ zone_dnskey = "".join(keys[ZONE]["dnskey"].split()[3:]) ++ return {"ZONE_DNSKEY": zone_dnskey} ++ ++ ++def _query(server, qname, qtype): ++ query = isctest.query.create(qname, qtype) ++ return isctest.query.tcp(query, server, attempts=1, timeout=5) ++ ++ ++def _rrset(response, section, owner, rdtype, covers=None): ++ if covers is None: ++ return response.get_rrset( ++ section, dns.name.from_text(owner), dns.rdataclass.IN, rdtype ++ ) ++ return response.get_rrset( ++ section, ++ dns.name.from_text(owner), ++ dns.rdataclass.IN, ++ rdtype, ++ covers=covers, ++ ) ++ ++ ++def _has_a(response, section, owner, address): ++ rrset = _rrset(response, section, owner, dns.rdatatype.A) ++ return rrset is not None and any(rdata.address == address for rdata in rrset) ++ ++ ++def _check_rrsig(response, section, owner, rdtype, signer, labels=None): ++ rrsig = _rrset(response, section, owner, dns.rdatatype.RRSIG, covers=rdtype) ++ assert rrsig is not None, response.to_text() ++ assert rrsig[0].signer == dns.name.from_text(signer), response.to_text() ++ if labels is not None: ++ assert rrsig[0].labels == labels, response.to_text() ++ ++ ++def test_repro_5985_direct_findnoqname_addnoqname_mismatch_fixture(): ++ response = _query(AUTH, ATTACK, "A") ++ isctest.check.noerror(response) ++ assert _has_a(response, response.answer, ATTACK, FORGED_A), response.to_text() ++ _check_rrsig(response, response.answer, ATTACK, dns.rdatatype.A, CHILD, labels=1) ++ ++ assert _rrset(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC) ++ _check_rrsig(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC, CHILD) ++ assert _rrset(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC3) ++ assert ( ++ _rrset( ++ response, ++ response.authority, ++ NSEC_OWNER, ++ dns.rdatatype.RRSIG, ++ covers=dns.rdatatype.NSEC3, ++ ) ++ is None ++ ) ++ ++ ++def test_repro_5985_resolver_does_not_abort_on_noqname_type_mismatch(): ++ _query(RESOLVER, ATTACK, "A") ++ ++ response = _query(RESOLVER, ZONE, "SOA") ++ isctest.check.noerror(response) diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-13204-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-13204-02.patch new file mode 100644 index 0000000000..5bcd10474f --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-13204-02.patch @@ -0,0 +1,215 @@ +From: Matthijs Mekking +Date: Mon, 15 Jun 2026 14:55:29 +0200 +Subject: Update reproducer #5985 + +Update the llm generated reproducer: +- Move server.py into ans/ans1.py +- Remove unncessary named.conf configuration options +- Add comments describing the steps +- Rename system test + +(cherry picked from commit fd539807829dd7d2eb76c8b503083f5d84fec6f0) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/6c0e599ea85c0c53a4af09742e64e193da089bb4 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-13204 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-13204 + +CVE: CVE-2026-13204 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/6c0e599ea85c0c53a4af09742e64e193da089bb4] +Signed-off-by: Hitendra Prajapati +--- + .../ans1/ans.py} | 36 ++++++++++++++++------ + .../ns2/named.conf.j2 | 3 -- + .../tests_findnoqname_mismatch.py} | 26 ++++++++++------ + .../ans1/ans.py | 11 ------- + 4 files changed, 43 insertions(+), 33 deletions(-) + rename bin/tests/system/{repro_5985_findnoqname_runtime_check/server.py => dnssec_findnoqname_mismatch/ans1/ans.py} (85%) + rename bin/tests/system/{repro_5985_findnoqname_runtime_check => dnssec_findnoqname_mismatch}/ns2/named.conf.j2 (87%) + rename bin/tests/system/{repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py => dnssec_findnoqname_mismatch/tests_findnoqname_mismatch.py} (87%) + delete mode 100644 bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py + +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/server.py b/bin/tests/system/dnssec_findnoqname_mismatch/ans1/ans.py +similarity index 85% +rename from bin/tests/system/repro_5985_findnoqname_runtime_check/server.py +rename to bin/tests/system/dnssec_findnoqname_mismatch/ans1/ans.py +index 18d0ac1..b36fc83 100644 +--- a/bin/tests/system/repro_5985_findnoqname_runtime_check/server.py ++++ b/bin/tests/system/dnssec_findnoqname_mismatch/ans1/ans.py +@@ -66,9 +66,7 @@ def load_key() -> Key: + return Key(name(ZONE), private_key, dnskey) + + +-def rrset( +- owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str +-) -> dns.rrset.RRset: ++def rrset(owner: str, rdtype: dns.rdatatype.RdataType, *rdatas: str) -> dns.rrset.RRset: + return dns.rrset.from_text(owner, TTL, dns.rdataclass.IN, rdtype, *rdatas) + + +@@ -121,20 +119,30 @@ def add_ds_denial(response: dns.message.Message, key: Key) -> None: + + + def add_attack_answer(response: dns.message.Message) -> None: ++ """ ++ Crafted authoritative response to .evil.f217.hack./A ++ ++ ;; ANSWER ++ .evil.f217.hack. 300 IN A 192.0.2.217 ++ .evil.f217.hack. 300 IN RRSIG A 13 1 300 12345 evil.f217.hack. ++ ^^^ Labels = 1, qname has 4 labels, wildcard heuristic fires ++ ++ ;; AUTHORITY (single owner, three rdatasets in this wire order) ++ 00000000.evil.f217.hack. 300 IN NSEC zzz.evil.f217.hack. A RRSIG NSEC ++ 00000000.evil.f217.hack. 300 IN RRSIG NSEC 13 4 300 12345 evil.f217.hack. ++ 00000000.evil.f217.hack. 300 IN NSEC3 1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG ++ """ ++ # A + RRSIG + response.answer.append(rrset(ATTACK, dns.rdatatype.A, FORGED_A)) + response.answer.append(garbage_rrsig(ATTACK, dns.rdatatype.A, 1, CHILD)) +- ++ # NSEC + nsec = rrset( + NSEC_OWNER, + dns.rdatatype.NSEC, + f"{NSEC_NEXT} A RRSIG NSEC", + ) +- nsec3 = rrset( +- NSEC_OWNER, +- dns.rdatatype.NSEC3, +- "1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG", +- ) + response.authority.append(nsec) ++ # RRSIG(NSEC) + response.authority.append( + garbage_rrsig( + NSEC_OWNER, +@@ -143,6 +151,12 @@ def add_attack_answer(response: dns.message.Message) -> None: + CHILD, + ) + ) ++ # NSEC3 ++ nsec3 = rrset( ++ NSEC_OWNER, ++ dns.rdatatype.NSEC3, ++ "1 0 0 - VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV A RRSIG", ++ ) + response.authority.append(nsec3) + + +@@ -187,3 +201,7 @@ def main() -> None: + server = AsyncDnsServer(default_aa=True) + server.install_response_handlers(RuntimeCheckHandler(load_key())) + server.run() ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/ns2/named.conf.j2 b/bin/tests/system/dnssec_findnoqname_mismatch/ns2/named.conf.j2 +similarity index 87% +rename from bin/tests/system/repro_5985_findnoqname_runtime_check/ns2/named.conf.j2 +rename to bin/tests/system/dnssec_findnoqname_mismatch/ns2/named.conf.j2 +index 7d6fc84..f4fbd8a 100644 +--- a/bin/tests/system/repro_5985_findnoqname_runtime_check/ns2/named.conf.j2 ++++ b/bin/tests/system/dnssec_findnoqname_mismatch/ns2/named.conf.j2 +@@ -10,9 +10,6 @@ options { + listen-on-v6 { none; }; + recursion yes; + dnssec-validation yes; +- trust-anchor-telemetry no; +- resolver-query-timeout 5000; +- qname-minimization off; + }; + + controls { +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py b/bin/tests/system/dnssec_findnoqname_mismatch/tests_findnoqname_mismatch.py +similarity index 87% +rename from bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py +rename to bin/tests/system/dnssec_findnoqname_mismatch/tests_findnoqname_mismatch.py +index 0e7d71c..f3e332a 100644 +--- a/bin/tests/system/repro_5985_findnoqname_runtime_check/tests_repro_5985_findnoqname_runtime_check.py ++++ b/bin/tests/system/dnssec_findnoqname_mismatch/tests_findnoqname_mismatch.py +@@ -18,6 +18,7 @@ import dns.rdatatype + import pytest + + import isctest ++import isctest.mark + + ZONE = "f217.test." + CHILD = f"evil.{ZONE}" +@@ -27,12 +28,15 @@ FORGED_A = "192.0.2.217" + AUTH = "10.53.0.1" + RESOLVER = "10.53.0.2" + +-pytestmark = pytest.mark.extra_artifacts( +- [ +- "ans*/ans.run", +- "keys.json", +- ] +-) ++pytestmark = [ ++ isctest.mark.with_ecdsa_deterministic, ++ pytest.mark.extra_artifacts( ++ [ ++ "ans1/ans.run", ++ "ans1/keys.json", ++ ] ++ ), ++] + + + def _make_key(): +@@ -55,7 +59,7 @@ def _make_key(): + + def bootstrap(): + keys = {ZONE: _make_key()} +- Path("keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") ++ Path("ans1/keys.json").write_text(json.dumps(keys, indent=2), encoding="ascii") + zone_dnskey = "".join(keys[ZONE]["dnskey"].split()[3:]) + return {"ZONE_DNSKEY": zone_dnskey} + +@@ -92,14 +96,16 @@ def _check_rrsig(response, section, owner, rdtype, signer, labels=None): + assert rrsig[0].labels == labels, response.to_text() + + +-def test_repro_5985_direct_findnoqname_addnoqname_mismatch_fixture(): ++def test_malicious_findnoqname_addnoqname_mismatch(): + response = _query(AUTH, ATTACK, "A") + isctest.check.noerror(response) + assert _has_a(response, response.answer, ATTACK, FORGED_A), response.to_text() + _check_rrsig(response, response.answer, ATTACK, dns.rdatatype.A, CHILD, labels=1) + ++ # Has NSEC + assert _rrset(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC) + _check_rrsig(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC, CHILD) ++ # Has NSEC3 + assert _rrset(response, response.authority, NSEC_OWNER, dns.rdatatype.NSEC3) + assert ( + _rrset( +@@ -113,8 +119,8 @@ def test_repro_5985_direct_findnoqname_addnoqname_mismatch_fixture(): + ) + + +-def test_repro_5985_resolver_does_not_abort_on_noqname_type_mismatch(): ++def test_resolver_findnoqname_addnoqname_mismatch(): ++ # Send one trigger query + _query(RESOLVER, ATTACK, "A") +- + response = _query(RESOLVER, ZONE, "SOA") + isctest.check.noerror(response) +diff --git a/bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py b/bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py +deleted file mode 100644 +index cb01c8a..0000000 +--- a/bin/tests/system/repro_5985_findnoqname_runtime_check/ans1/ans.py ++++ /dev/null +@@ -1,11 +0,0 @@ +-#!/usr/bin/python3 +- +-# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +-# +-# SPDX-License-Identifier: MPL-2.0 +- +-from server import main +- +- +-if __name__ == "__main__": +- main() diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-13204-03.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-13204-03.patch new file mode 100644 index 0000000000..59e200fc87 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-13204-03.patch @@ -0,0 +1,161 @@ +From: Evan Hunt +Date: Wed, 13 May 2026 20:45:57 -0700 +Subject: 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) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/48f5aa5fb3746d6194edcc57e8792a8b3cc3b454 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-13204 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-13204 + +CVE: CVE-2026-13204 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/48f5aa5fb3746d6194edcc57e8792a8b3cc3b454] +Signed-off-by: Hitendra Prajapati +--- + lib/dns/rbtdb.c | 10 +++++++--- + lib/dns/rdatalist.c | 33 ++++++++++++++++----------------- + lib/dns/resolver.c | 4 +++- + lib/ns/query.c | 3 +-- + 4 files changed, 27 insertions(+), 23 deletions(-) + +diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c +index 0b85479..c922df5 100644 +--- a/lib/dns/rbtdb.c ++++ b/lib/dns/rbtdb.c +@@ -6946,7 +6946,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; +@@ -6958,7 +6958,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); +@@ -6984,7 +6986,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 98036f9..2cca8d6 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; + } + /* +@@ -238,6 +236,7 @@ isc__rdatalist_addnoqname(dns_rdataset_t *rdataset, const dns_name_t *name) { + rdataset->ttl = neg->ttl = negsig->ttl = ttl; + rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; + rdataset->private6 = name; ++ + return ISC_R_SUCCESS; + } + +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 06c779e..01c4a00 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -5910,7 +5910,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 f0e5244..c4fe7c8 100644 +--- a/lib/ns/query.c ++++ b/lib/ns/query.c +@@ -7941,8 +7941,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); diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-13321-01.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-13321-01.patch new file mode 100644 index 0000000000..90a17f2a08 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-13321-01.patch @@ -0,0 +1,401 @@ +From: =?utf-8?q?Ayd=C4=B1n_Mercan?= +Date: Wed, 6 May 2026 16:54:57 +0300 +Subject: Add system test for out-of-zone nsec dnssec bypass + +A malicious zone with out-of-zone NSEC entries can get a DNSSEC +validating resolver's cache to cover the victim zone for non-existence +and prevent nameserver queries without DNSSEC failure. + +Test for this case with an `evil.test` zone that tries to cover the +`victim.test` zone. + +(cherry picked from commit 654f9773c0af59965c343bdfeb096b3dffe9dd53) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/c969ad2c17b43dd999e358bfeb280d3df6fab822 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-13321 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-13321 + +CVE: CVE-2026-13321 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/c969ad2c17b43dd999e358bfeb280d3df6fab822] +Signed-off-by: Hitendra Prajapati +--- + .../ns1/named.conf.j2} | 7 +- + .../ns1/root.db} | 11 +- + .../ns1/test.db} | 15 +- + .../ns2/named.conf.j2} | 6 +- + .../ns2/victim.db} | 8 +- + .../template.db.in => dnssec_bypass/ns3/evil.db} | 22 ++- + .../ns3/named.conf.j2} | 6 +- + .../ns4/named.conf.j2} | 9 +- + bin/tests/system/dnssec_bypass/tests_bypass.py | 152 +++++++++++++++++++++ + 9 files changed, 202 insertions(+), 34 deletions(-) + copy bin/tests/system/{allow_query/ns1/named.conf.in => dnssec_bypass/ns1/named.conf.j2} (87%) + copy bin/tests/system/{dupsigs/ns1/signing.test.db.in => dnssec_bypass/ns1/root.db} (72%) + copy bin/tests/system/{dupsigs/ns1/signing.test.db.in => dnssec_bypass/ns1/test.db} (69%) + copy bin/tests/system/{runtime/ns2/named-alt4.conf.in => dnssec_bypass/ns2/named.conf.j2} (89%) + copy bin/tests/system/{dnssec/ns2/cdnskey.secure.db.in => dnssec_bypass/ns2/victim.db} (79%) + copy bin/tests/system/{checkds/ns9/template.db.in => dnssec_bypass/ns3/evil.db} (54%) + copy bin/tests/system/{allow_query/ns1/named.conf.in => dnssec_bypass/ns3/named.conf.j2} (88%) + copy bin/tests/system/{rrsetorder/ns4/named.conf.in => dnssec_bypass/ns4/named.conf.j2} (86%) + create mode 100644 bin/tests/system/dnssec_bypass/tests_bypass.py + +diff --git a/bin/tests/system/allow_query/ns1/named.conf.in b/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 +similarity index 87% +copy from bin/tests/system/allow_query/ns1/named.conf.in +copy to bin/tests/system/dnssec_bypass/ns1/named.conf.j2 +index dd786e2..59ced18 100644 +--- a/bin/tests/system/allow_query/ns1/named.conf.in ++++ b/bin/tests/system/dnssec_bypass/ns1/named.conf.j2 +@@ -20,7 +20,12 @@ options { + dnssec-validation no; + }; + ++zone "test." { ++ type primary; ++ file "test.db.signed"; ++}; ++ + zone "." { + type primary; +- file "root.db"; ++ file "root.db.signed"; + }; +diff --git a/bin/tests/system/dupsigs/ns1/signing.test.db.in b/bin/tests/system/dnssec_bypass/ns1/root.db +similarity index 72% +copy from bin/tests/system/dupsigs/ns1/signing.test.db.in +copy to bin/tests/system/dnssec_bypass/ns1/root.db +index b522b6f..8d98a04 100644 +--- a/bin/tests/system/dupsigs/ns1/signing.test.db.in ++++ b/bin/tests/system/dnssec_bypass/ns1/root.db +@@ -10,9 +10,10 @@ + ; information regarding copyright ownership. + + $TTL 3600 +-@ IN SOA ns root.ns 1996072700 3600 1800 86400 60 +-@ NS ns +-ns A 127.0.0.1 +-ns AAAA ::1 ++. IN SOA a.nil. a.nil. 1 3600 600 86400 300 ++. IN NS a.root-servers.nil. + +-$GENERATE 0-499 a${0,4,d} AAAA ::$ ++a.root-servers.nil. IN A 10.53.0.1 ++ ++test. IN NS ns1.test. ++ns1.test. IN A 10.53.0.1 +diff --git a/bin/tests/system/dupsigs/ns1/signing.test.db.in b/bin/tests/system/dnssec_bypass/ns1/test.db +similarity index 69% +copy from bin/tests/system/dupsigs/ns1/signing.test.db.in +copy to bin/tests/system/dnssec_bypass/ns1/test.db +index b522b6f..6efcd95 100644 +--- a/bin/tests/system/dupsigs/ns1/signing.test.db.in ++++ b/bin/tests/system/dnssec_bypass/ns1/test.db +@@ -9,10 +9,15 @@ + ; See the COPYRIGHT file distributed with this work for additional + ; information regarding copyright ownership. + ++$ORIGIN test. + $TTL 3600 +-@ IN SOA ns root.ns 1996072700 3600 1800 86400 60 +-@ NS ns +-ns A 127.0.0.1 +-ns AAAA ::1 + +-$GENERATE 0-499 a${0,4,d} AAAA ::$ ++@ IN SOA a a 1 3600 600 86400 300 ++ IN NS ns1.test. ++ns1 IN A 10.53.0.1 ++ ++evil IN NS ns1.evil ++ns1.evil IN A 10.53.0.3 ++ ++victim IN NS ns1.victim ++ns1.victim IN A 10.53.0.2 +diff --git a/bin/tests/system/runtime/ns2/named-alt4.conf.in b/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 +similarity index 89% +copy from bin/tests/system/runtime/ns2/named-alt4.conf.in +copy to bin/tests/system/dnssec_bypass/ns2/named.conf.j2 +index 4c0312a..e81cee7 100644 +--- a/bin/tests/system/runtime/ns2/named-alt4.conf.in ++++ b/bin/tests/system/dnssec_bypass/ns2/named.conf.j2 +@@ -12,7 +12,6 @@ + */ + + options { +- directory "./nope"; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; +@@ -20,3 +19,8 @@ options { + recursion no; + dnssec-validation no; + }; ++ ++zone "victim.test." { ++ type primary; ++ file "victim.db.signed"; ++}; +diff --git a/bin/tests/system/dnssec/ns2/cdnskey.secure.db.in b/bin/tests/system/dnssec_bypass/ns2/victim.db +similarity index 79% +copy from bin/tests/system/dnssec/ns2/cdnskey.secure.db.in +copy to bin/tests/system/dnssec_bypass/ns2/victim.db +index aa3aaab..edcc234 100644 +--- a/bin/tests/system/dnssec/ns2/cdnskey.secure.db.in ++++ b/bin/tests/system/dnssec_bypass/ns2/victim.db +@@ -9,6 +9,10 @@ + ; See the COPYRIGHT file distributed with this work for additional + ; information regarding copyright ownership. + ++$ORIGIN victim.test. + $TTL 3600 +-@ SOA ns2.example. . 1 3600 1200 86400 1200 +-@ NS ns2.example. ++ ++@ IN SOA ns1 hostmaster 1 3600 600 86400 2147483647 ++ IN NS ns1 ++ ++ns1 IN A 10.53.0.2 +diff --git a/bin/tests/system/checkds/ns9/template.db.in b/bin/tests/system/dnssec_bypass/ns3/evil.db +similarity index 54% +copy from bin/tests/system/checkds/ns9/template.db.in +copy to bin/tests/system/dnssec_bypass/ns3/evil.db +index cf06015..618f9d3 100644 +--- a/bin/tests/system/checkds/ns9/template.db.in ++++ b/bin/tests/system/dnssec_bypass/ns3/evil.db +@@ -9,19 +9,15 @@ + ; See the COPYRIGHT file distributed with this work for additional + ; information regarding copyright ownership. + ++$ORIGIN evil.test. + $TTL 300 +-@ IN SOA mname1. . ( +- 1 ; serial +- 20 ; refresh (20 seconds) +- 20 ; retry (20 seconds) +- 1814400 ; expire (3 weeks) +- 3600 ; minimum (1 hour) +- ) + +- NS ns9 +-ns9 A 10.53.0.9 +- +-a A 10.0.0.1 +-b A 10.0.0.2 +-c A 10.0.0.3 ++@ IN SOA ns1 hostmaster 1 3600 600 86400 300 ++ IN NS ns1 ++; Try to poison the victim zone in a resolver cache. ++; If admitted, the aggressive NSEC cache will accept a range such as ++; [evil.test, b.victim.test) and will cause the victim nameserver to ++; be never queried. ++ IN NSEC b.victim.test. NS SOA RRSIG NSEC DNSKEY + ++ns1 IN A 10.53.0.3 +diff --git a/bin/tests/system/allow_query/ns1/named.conf.in b/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 +similarity index 88% +copy from bin/tests/system/allow_query/ns1/named.conf.in +copy to bin/tests/system/dnssec_bypass/ns3/named.conf.j2 +index dd786e2..17d3e18 100644 +--- a/bin/tests/system/allow_query/ns1/named.conf.in ++++ b/bin/tests/system/dnssec_bypass/ns3/named.conf.j2 +@@ -14,13 +14,13 @@ + options { + port @PORT@; + pid-file "named.pid"; +- listen-on { 10.53.0.1; }; ++ listen-on { 10.53.0.3; }; + listen-on-v6 { none; }; + recursion no; + dnssec-validation no; + }; + +-zone "." { ++zone "evil.test." { + type primary; +- file "root.db"; ++ file "evil.db.signed"; + }; +diff --git a/bin/tests/system/rrsetorder/ns4/named.conf.in b/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 +similarity index 86% +copy from bin/tests/system/rrsetorder/ns4/named.conf.in +copy to bin/tests/system/dnssec_bypass/ns4/named.conf.j2 +index d5fc527..039695d 100644 +--- a/bin/tests/system/rrsetorder/ns4/named.conf.in ++++ b/bin/tests/system/dnssec_bypass/ns4/named.conf.j2 +@@ -19,13 +19,14 @@ options { + pid-file "named.pid"; + listen-on { 10.53.0.4; }; + listen-on-v6 { none; }; ++ allow-transfer { any; }; + recursion yes; + dnssec-validation yes; +- notify yes; +- rrset-order { +- class IN type A name "host.example.com" order random; +- }; ++ synth-from-dnssec yes; ++}; + ++trust-anchors { ++ @root.domain@ @root.type@ @root.contents@; + }; + + zone "." { +diff --git a/bin/tests/system/dnssec_bypass/tests_bypass.py b/bin/tests/system/dnssec_bypass/tests_bypass.py +new file mode 100644 +index 0000000..c41bb7e +--- /dev/null ++++ b/bin/tests/system/dnssec_bypass/tests_bypass.py +@@ -0,0 +1,152 @@ ++# 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 datetime import datetime, timedelta, timezone ++ ++import shutil ++ ++from cryptography.hazmat.primitives.asymmetric import ec ++ ++import dns.dnssec ++import dns.name ++import dns.rdataclass ++import dns.rdataset ++import dns.rdatatype ++import dns.rrset ++import dns.zone ++ ++from isctest.run import EnvCmd ++ ++import isctest ++ ++TTL = 3600 ++ ++ ++def bootstrap(): ++ keygen = EnvCmd("KEYGEN", "-q -a ECDSA256") ++ signer = EnvCmd("SIGNER", "-S -g -O full") ++ ++ def sign_regular_zone(ns: str, zone: str, database: str) -> isctest.kasp.Key: ++ isctest.log.info(f"{zone}: generate keys") ++ keygen(zone, cwd=ns).out.strip() ++ ksk = keygen(f"-f KSK {zone}", cwd=ns).out.strip() ++ ++ isctest.log.info(f"{zone}: sign zone") ++ signer(f"-o {zone} {database}", cwd=ns) ++ ++ if ns != "ns1": ++ shutil.copy(f"{ns}/dsset-{zone}", f"ns1/dsset-{zone}") ++ shutil.copy(f"{ns}/{ksk}.key", f"ns1/{ksk}.key") ++ ++ return isctest.kasp.Key(ksk, keydir=ns) ++ ++ # dnssec-signzone and `dns.dnssec.sign_zone` correctly disregard the invalid ++ # NSEC entries when signing the zone. However, for this test we actualy *want* ++ # to serve invalid yet signed zones. To accomplish this we sign the zone and then ++ # replace the correct entries with the faulty ones accompanied by its RRSIG. ++ # ++ # TODO(aydin): move this to `isctest` to sign broken zones ++ def sign_rogue_zone(ns: str, zone: str, database: str) -> None: ++ # Read zone. ++ origin = dns.name.from_text(zone) ++ data = dns.zone.from_file(f"{ns}/{database}", origin=origin, relativize=False) ++ ++ # Get key for signing. ++ isctest.log.info(f"{zone}: generate keys") ++ private_key = ec.generate_private_key(ec.SECP256R1()) ++ dnskey = dns.dnssec.make_dnskey( ++ public_key=private_key.public_key(), ++ algorithm=dns.dnssec.Algorithm.ECDSAP256SHA256, ++ flags=257, ++ ) ++ ++ # Sign zone. ++ isctest.log.info(f"{zone}: sign zone") ++ now = datetime.now(timezone.utc) ++ inception = now - timedelta(hours=1) ++ expiration = now + timedelta(days=30) ++ ++ for name, node in data.nodes.items(): ++ owner = name.derelativize(origin) ++ rdatasets = list(node.rdatasets) ++ ++ for rdataset in rdatasets: ++ rrset = dns.rrset.RRset(owner, rdataset.rdclass, rdataset.rdtype) ++ rrset.update(rdataset) ++ ++ rrsig = dns.dnssec.sign( ++ rrset=rrset, ++ private_key=private_key, ++ signer=origin, ++ dnskey=dnskey, ++ inception=inception, ++ expiration=expiration, ++ deterministic=False, ++ ) ++ ++ rdataset = dns.rdataset.Rdataset(rrset.rdclass, dns.rdatatype.RRSIG) ++ rdataset.add(rrsig, rrset.ttl) ++ node.replace_rdataset(rdataset) ++ ++ # Sign DNSKEY RRset. ++ dnskey_rrset = dns.rrset.RRset(origin, dns.rdataclass.IN, dns.rdatatype.DNSKEY) ++ dnskey_rrset.add(dnskey, ttl=TTL) ++ ++ apex_node = data.nodes[origin] ++ apex_node.replace_rdataset(dnskey_rrset) ++ ++ rrsig = dns.dnssec.sign( ++ rrset=dnskey_rrset, ++ private_key=private_key, ++ signer=origin, ++ dnskey=dnskey, ++ inception=inception, ++ expiration=expiration, ++ deterministic=False, ++ ) ++ rdataset = dns.rdataset.Rdataset(rrset.rdclass, dns.rdatatype.RRSIG) ++ rdataset.add(rrsig, dnskey_rrset.ttl) ++ apex_node.replace_rdataset(rdataset) ++ ++ # Output zone. ++ data.to_file(f"{ns}/{database}.signed", relativize=False) ++ ++ # Output DS. ++ ds = dns.dnssec.make_ds(name=origin, key=dnskey, algorithm="SHA256") ++ with open(f"ns1/dsset-{zone}", "w", encoding="utf-8") as f: ++ f.write(f"{zone} {TTL} IN DS {ds.to_text()}\n") ++ ++ sign_rogue_zone("ns3", "evil.test.", "evil.db") ++ sign_regular_zone("ns2", "victim.test.", "victim.db") ++ sign_regular_zone("ns1", "test.", "test.db") ++ root_ksk = sign_regular_zone("ns1", ".", "root.db") ++ ++ return { ++ "root": root_ksk.into_ta("static-key"), ++ } ++ ++ ++def test_out_of_zone_nsec(ns4): ++ isctest.log.info("trying to poison aggressive nsec cache") ++ msg = isctest.query.create("nx.evil.test", "A") ++ res = isctest.query.tcp(msg, ns4.ip) ++ isctest.check.noadflag(res) ++ ++ isctest.log.info("query victim from recursive") ++ msg = isctest.query.create("victim.test", "SOA") ++ res = isctest.query.tcp(msg, ns4.ip, attempts=1) ++ isctest.check.noerror(res) ++ isctest.check.adflag(res) ++ isctest.check.rr_count_eq(res.answer, 2) ++ ++ isctest.log.info("checking for query history on victim nameserver") ++ with open("ns2/named.run", "r", encoding="utf-8") as f: ++ assert "(victim.test): query 'victim.test/SOA/IN' approved" in f.read() diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-13321-02.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-13321-02.patch new file mode 100644 index 0000000000..a9bf3521b0 --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-13321-02.patch @@ -0,0 +1,88 @@ +From: =?utf-8?q?Ayd=C4=B1n_Mercan?= +Date: Thu, 7 May 2026 18:59:20 +0300 +Subject: Reject out-of-zone NSEC next owner names + +When verifying DNSSEC records, make sure that a next owner name of +an NSEC record is a subdomain of the signer field. + +This follows the specification RFC 4034, section 4.1.1: + + Owner names of RRsets for which the given zone is not authoritative + (such as glue records) MUST NOT be listed in the Next Domain Name + unless at least one authoritative RRset exists at the same owner + name. + +While the above paragraph is intended for glue records, it also +applies to out-of-zone data. + +(cherry picked from commit 4065512d25b71605b9502bb69dfb903776d35aa9) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/058023c66f11d78590d4aa8c4f98946c4c965e21 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-13321 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-13321 + +CVE: CVE-2026-13321 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/058023c66f11d78590d4aa8c4f98946c4c965e21] +Signed-off-by: Hitendra Prajapati +--- + lib/dns/dnssec.c | 13 +++++++++++++ + lib/dns/include/dns/dnssec.h | 6 ++++++ + 2 files changed, 19 insertions(+) + +diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c +index 9b9b1f2..5acaea9 100644 +--- a/lib/dns/dnssec.c ++++ b/lib/dns/dnssec.c +@@ -357,8 +357,10 @@ isc_result_t + dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + bool ignoretime, unsigned int maxbits, isc_mem_t *mctx, + dns_rdata_t *sigrdata, dns_name_t *wild) { ++ dns_rdata_nsec_t nsec; + dns_rdata_rrsig_t sig; + dns_fixedname_t fnewname; ++ dns_rdata_t rdata = DNS_RDATA_INIT; + isc_region_t r; + isc_buffer_t envbuf; + dns_rdata_t *rdatas; +@@ -464,6 +466,17 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + } + break; + } ++ /* ++ * Check for out of zone NSEC entries. ++ */ ++ if (set->type == dns_rdatatype_nsec) { ++ RETERR(dns_rdataset_first(set)); ++ dns_rdataset_current(set, &rdata); ++ RETERR(dns_rdata_tostruct(&rdata, &nsec, NULL)); ++ if (!dns_name_issubdomain(&nsec.next, &sig.signer)) { ++ return DNS_R_NOVALIDNSEC; ++ } ++ } + + again: + ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, +diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h +index cb8fd9d..2be11b9 100644 +--- a/lib/dns/include/dns/dnssec.h ++++ b/lib/dns/include/dns/dnssec.h +@@ -151,6 +151,9 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + * this record, as this requires a resolver or database. + * If 'ignoretime' is true, temporal validity will not be checked. + * ++ * If 'set' is of type NSEC, this function also verifies that the ++ * Next Name is a subdomain of the Signer's Name from 'sigrdata'. ++ * + * 'maxbits' specifies the maximum number of rsa exponent bits accepted. + * + * Requires: +@@ -173,6 +176,9 @@ dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data (either + * it is not a zone key or its flags prevent + * authentication) ++ * ++ *\li #DNS_R_NOVALIDNSEC - the NSEC rdata is not valid ++ *\li #DNS_R_KEYUNAUTHORIZED - the key cannot sign this data + *\li DST_R_* + */ + diff --git a/meta/recipes-connectivity/bind/bind/CVE-2026-13321-03.patch b/meta/recipes-connectivity/bind/bind/CVE-2026-13321-03.patch new file mode 100644 index 0000000000..c85e92d22d --- /dev/null +++ b/meta/recipes-connectivity/bind/bind/CVE-2026-13321-03.patch @@ -0,0 +1,203 @@ +From: =?utf-8?q?Ayd=C4=B1n_Mercan?= +Date: Tue, 12 May 2026 14:54:09 +0300 +Subject: change dns_nsec_requiredtypespresent to dns_nsec_is_legal + +Change `dns_nsec_requiredtypespresent` to `dns_nsec_is_legal` as a +function for checking multiple NSEC validity rules. + +Currently we now additionally check for out-of-zone NSEC entries. + +(cherry picked from commit be2a6a497312469890b552907d039d2de0b44ccc) + +Origin: https://gitlab.isc.org/isc-projects/bind9/-/commit/f751e19a30d107f04c2f644aff9f8dab8fed03ab +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-13321 +Bug-Freexian-Security: https://deb.freexian.com/extended-lts/tracker/CVE-2026-13321 + +CVE: CVE-2026-13321 +Upstream-Status: Backport [https://gitlab.isc.org/isc-projects/bind9/-/commit/f751e19a30d107f04c2f644aff9f8dab8fed03ab] +Signed-off-by: Hitendra Prajapati +--- + lib/dns/include/dns/nsec.h | 18 ++++++++++++----- + lib/dns/nsec.c | 17 ++++++++++++---- + lib/dns/resolver.c | 48 ++++++++++++++++++++++++++++++++++++++++++++-- + lib/ns/query.c | 6 +++--- + 4 files changed, 75 insertions(+), 14 deletions(-) + +diff --git a/lib/dns/include/dns/nsec.h b/lib/dns/include/dns/nsec.h +index 50df8e4..1e71bf1 100644 +--- a/lib/dns/include/dns/nsec.h ++++ b/lib/dns/include/dns/nsec.h +@@ -119,13 +119,21 @@ dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name, + */ + + bool +-dns_nsec_requiredtypespresent(dns_rdataset_t *rdataset); +-/* +- * Return true if all the NSEC records in rdataset have both +- * NSEC and RRSIG present. ++dns_nsec_is_legal(dns_rdataset_t *rdataset, const dns_name_t *name); ++/**< ++ * \brief ++ * Validates a rdataset of type NSEC. + * +- * Requires: ++ * This functions checks for the following in the given rdataset: ++ * \li All NSEC records have both NSEC and RRSIG present ++ * \li All NSEC entries are under the `name` ++ * ++ * \par Requires: + * \li rdataset to be a NSEC rdataset. ++ * \li `name` is a valid dns_name_t ++ * ++ * \retval true if all the checks pass ++ * \retval false otherwise + */ + + ISC_LANG_ENDDECLS +diff --git a/lib/dns/nsec.c b/lib/dns/nsec.c +index 80ee8d7..5abcce5 100644 +--- a/lib/dns/nsec.c ++++ b/lib/dns/nsec.c +@@ -21,6 +21,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -497,8 +498,9 @@ dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name, + } + + bool +-dns_nsec_requiredtypespresent(dns_rdataset_t *nsecset) { +- dns_rdataset_t rdataset; ++dns_nsec_is_legal(dns_rdataset_t *nsecset, const dns_name_t *name) { ++ dns_rdataset_t rdataset = DNS_RDATASET_INIT; ++ dns_rdata_nsec_t nsec; + isc_result_t result; + bool found = false; + +@@ -513,12 +515,19 @@ dns_nsec_requiredtypespresent(dns_rdataset_t *nsecset) { + { + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_current(&rdataset, &rdata); +- if (!dns_nsec_typepresent(&rdata, dns_rdatatype_nsec) || +- !dns_nsec_typepresent(&rdata, dns_rdatatype_rrsig)) ++ ++ /* must never fail */ ++ result = dns_rdata_tostruct(&rdata, &nsec, NULL); ++ INSIST(result == ISC_R_SUCCESS); ++ ++ if (!dns_name_issubdomain(&nsec.next, name) || ++ !dns_nsec_typepresent(&rdata, dns_rdatatype_rrsig) || ++ !dns_nsec_typepresent(&rdata, dns_rdatatype_nsec)) + { + dns_rdataset_disassociate(&rdataset); + return false; + } ++ + found = true; + } + dns_rdataset_disassociate(&rdataset); +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 01c4a00..1bfd8bb 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -65,7 +65,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + + /* Detailed logging of fctx attach/detach */ +@@ -5620,6 +5622,36 @@ fctx_setresult(fetchctx_t *fctx, dns_rdataset_t *rdataset) { + return result; + } + ++static bool ++get_and_check_signer_name(dns_name_t *signer, dns_rdataset_t *sigrdataset) { ++ dns_rdata_rrsig_t rrsig; ++ isc_result_t result; ++ dns_rdata_t rdata; ++ ++ if (dns_rdataset_first(sigrdataset) != ISC_R_SUCCESS) { ++ return false; ++ } ++ ++ rdata = (dns_rdata_t)DNS_RDATA_INIT; ++ dns_rdataset_current(sigrdataset, &rdata); ++ result = dns_rdata_tostruct(&rdata, &rrsig, NULL); ++ INSIST(result == ISC_R_SUCCESS); ++ dns_name_copy(&rrsig.signer, signer); ++ ++ while (dns_rdataset_next(sigrdataset) == ISC_R_SUCCESS) { ++ rdata = (dns_rdata_t)DNS_RDATA_INIT; ++ dns_rdataset_current(sigrdataset, &rdata); ++ result = dns_rdata_tostruct(&rdata, &rrsig, NULL); ++ INSIST(result == ISC_R_SUCCESS); ++ ++ if (!dns_name_equal(signer, &rrsig.signer)) { ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + /* + * The validator has finished. + */ +@@ -5650,6 +5682,8 @@ validated(isc_task_t *task, isc_event_t *event) { + dns_fixedname_t fwild; + dns_name_t *wild = NULL; + dns_message_t *message = NULL; ++ dns_fixedname_t fsigner; ++ dns_name_t *signer = NULL; + + UNUSED(task); /* for now */ + +@@ -6038,10 +6072,20 @@ answer_response: + } + + /* +- * Don't cache NSEC if missing NSEC or RRSIG types. ++ * Don't cache if all the RRSIGs don't have the same ++ * signer. ++ */ ++ signer = dns_fixedname_initname(&fsigner); ++ if (!get_and_check_signer_name(signer, sigrdataset)) { ++ continue; ++ } ++ ++ /* ++ * Don't cache NSEC if missing NSEC or RRSIG ++ * types. + */ + if (rdataset->type == dns_rdatatype_nsec && +- !dns_nsec_requiredtypespresent(rdataset)) ++ !dns_nsec_is_legal(rdataset, signer)) + { + continue; + } +diff --git a/lib/ns/query.c b/lib/ns/query.c +index c4fe7c8..1985f4e 100644 +--- a/lib/ns/query.c ++++ b/lib/ns/query.c +@@ -10356,10 +10356,10 @@ query_coveringnsec(query_ctx_t *qctx) { + } + + /* +- * If NSEC or RRSIG are missing from the type map +- * reject the NSEC RRset. ++ * Check that the NSEC entry is legal. ++ * (NSEC + RRSIG present and the entry isn't out-of-zone) + */ +- if (!dns_nsec_requiredtypespresent(qctx->rdataset)) { ++ if (!dns_nsec_is_legal(qctx->rdataset, signer)) { + goto cleanup; + } + diff --git a/meta/recipes-connectivity/bind/bind_9.18.49.bb b/meta/recipes-connectivity/bind/bind_9.18.49.bb index b048ba6559..32205e4104 100644 --- a/meta/recipes-connectivity/bind/bind_9.18.49.bb +++ b/meta/recipes-connectivity/bind/bind_9.18.49.bb @@ -35,6 +35,12 @@ SRC_URI = "https://ftp.isc.org/isc/bind9/${PV}/${BPN}-${PV}.tar.xz \ file://CVE-2026-11721-03.patch \ file://CVE-2026-12617-01.patch \ file://CVE-2026-12617-02.patch \ + file://CVE-2026-13204-01.patch \ + file://CVE-2026-13204-02.patch \ + file://CVE-2026-13204-03.patch \ + file://CVE-2026-13321-01.patch \ + file://CVE-2026-13321-02.patch \ + file://CVE-2026-13321-03.patch \ " SRC_URI[sha256sum] = "c43ce4548ebed788cd9df63658a7de105ceafba43fcd63fa352b1093e525cd24"