Re: [BLFS Trac] #23637: bind9 bind 9.20.26

BLFS Trac ([email protected] via blfs-book Mailing List) <[email protected]> Thu, 23 Jul 2026 22:24:01 -0000
Newsgroups gmane.linux.lfs.beyond.book
Message-ID <[email protected]>
#23637: bind9 bind 9.20.26
-------------------------+--------------------------
 Reporter:  Bruce Dubbs  |       Owner:  Bruce Dubbs
     Type:  enhancement  |      Status:  assigned
 Priority:  high         |   Milestone:  13.1
Component:  BOOK         |     Version:  git
 Severity:  high         |  Resolution:
 Keywords:               |
-------------------------+--------------------------
Changes (by Bruce Dubbs):

 * owner:  blfs-book => Bruce Dubbs
 * status:  new => assigned

Comment:

 BIND 9.20.26

 Security Fixes

 - [CVE-2026-11331] Fix handling of rpz CNAME expansion that returns name
   too long.

   Previously, if the expansion of a wildcard CNAME RPZ policy resulted
   in a name that exceeded the length limit, a self referential CNAME and
   the original address record were returned, allowing the policy to be
   bypassed.  In branches up to 9.20, this also left query processing in
   an inconsistent state which could trigger an assertion failure.  We
   now return a YXDOMAIN response, without the address.

 - [CVE-2026-11721] Invalid signed wildcard records were being accepted.

   Signed wildcard responses in which the Labels field in the `RRSIG`
   record was less than the number of labels in the Signer Name field
   were being incorrectly accepted. This in turn broke
   `synth-from-dnssec`, which depends on such records being correctly
   validated. This has been fixed.

 - [CVE-2026-13321] Fix DNSSEC validation bypass via out-of-zone NSEC
   Next Field.

   A malicious zone with out-of-zone NSEC next owner names can cause a
   DNSSEC validating resolver to cache such record and, if
   `synth-from-dnssec` is enabled, to generate negative answers for any
   zone that is covered by the range.


 - [CVE-2026-10723] Correct verification of NSEC3 signer name.

   BIND 9 accepted child-zone NSEC3 records where the first label equals
   the hash of the parent zone as valid parent-zone closest encloser
   proofs. This has been fixed.

 - [CVE-2026-12617] Do no assert for some specifics CNAME and DNAME
   queries.

   A bug in the resolver's handling of certain cached DNAME and CNAME
   responses could cause named to trigger an assertion failure and exit.
   An attacker controlling a domain name and the authoritative DNS server
   it is hosted on could exploit this behavior to cause a
   denial-of-service. This vulnerability has been fixed.

 - [CVE-2026-10822] Malformed DNSKEY records could trigger an assertion.

   Previously, `dns_name_fromwire()` did not honor the record boundary
   when reading names from the wire, allowing malformed records to be
   accepted when they should not have been. In particular, malformed
   DNSKEY records could trigger an assertion failure when being printed.
   This has been fixed.

 - Reclaim memory promptly when DNSSEC validations are canceled.

   When a resolver is flooded with queries that require DNSSEC validation
   — for example during a random-subdomain attack — many of those
   validations are canceled before they complete. Previously a canceled
   validation still kept its place in the internal work queue and held
   the associated response in memory until that queued work eventually
   ran, so memory could climb sharply under sustained load. The canceled
   work is now dropped as soon as the validation is canceled, releasing
   the memory it was holding.

 - [CVE-2026-11605] Prevent excessive validation work from crafted
   negative responses.

   A validating resolver could be made to perform a large amount of
   DNSSEC validation work in response to a single answer, consuming
   excessive CPU. A malicious authoritative server triggers this by
   returning a signed negative answer (NXDOMAIN or NODATA) padded with
   many denial-of-existence proof records, which the resolver continued
   to verify beyond its per-query validation limit. It now enforces that
   limit on negative answers and returns SERVFAIL once the limit is
   reached.

 - [CVE-2026-11622] Prevent cache exhaustion under sustained attack.

   The cache memory can become exhausted with expired entries whose
   memory is not released due to a sustained attack on the same DNS name
   that prevents the cleanup. This has been fixed.

 New Features

 - Print OS platform in "named -V"

   The "running on" line emitted by `named -V` (as well as the startup
   log and `rndc status`, which share the same source) now appends the
   PRETTY_NAME value from /etc/os-release in parentheses after the uname
   output, e.g.:

   running on Linux x86_64 6.19.14-... (Fedora Linux 42 (Workstation
   Edition))

   This helps disambiguate environments where the kernel string is not a
   reliable indicator of the userspace, such as RHEL clones and
   containers whose kernel does not match the host OS.

   When /etc/os-release is absent, /usr/lib/os-release is tried as a
   fallback per the systemd os-release(5) specification. When neither is
   available or no PRETTY_NAME is found, the output is unchanged.

 Removed Features

 - Remove the secondary validator in query.c.

   Previously, when the additional section of a response was being
   populated, if cached data was found with pending trust, it would be
   opportunistically validated. The code implementing this validation was
   not quite formally correct. Rather than fixing it, the code has been
   removed: RRsets with pending trust are now omitted from responses.

 Feature Changes

 - Rework isc_work as per-loop, per-lane cancelable worker threads.

   Fold the libuv thread pool and the per-loop isc_helper threads into a
   single isc_work pool. Each (loop, lane) gets its own SPSC queue and
   worker, which drops the shared-queue contention, and the FAST/SLOW
   lanes keep short crypto tasks off the long blocking ones (zone
   dump/load, xfrin). isc_work jobs are now cancelable: isc_work_cancel()
   tombstones a still-queued job and its after_cb fires with
   ISC_R_CANCELED, so abandoned work can be dropped instead of run to
   completion.

 Bug Fixes

 - Fix a bug in DNS UPDATE processing with inline-signing enabled.

   In rare cases the :iscman:`named` process could terminate unexpectedly
   when processing authorized DNS UPDATE messages in quick procession
   which are updating a zone with inline-signing enabled. This has been
   fixed.

 - Properly detect private records before copying.

   We were triggering an assertion when trying to copy a private record
   to a buffer for modifying.  Extend the private type detection and copy
   the contents after we have rejected invalid private records.

 - Tighten  referral DS acceptance.

   Named was accepting DS records for sibling zones when it shouldn't
   have.  This has been fixed.

 - Don't synthesize negative responses with pending NSEC.

   If an NSEC record has not yet been validated and is cached with trust
   pending, don't use it to synthesize negative responses.

 - Check that an NSEC signer is at or above the name to be validated.

   Add a check that an NSEC record being used as a proof of nonexistence
   for a given name is not signed by a name lower in the DNS hierarchy
   than the one in question.

 - Don't evict DNSSEC-validated cache data on a CD=1 NXDOMAIN.

   When a client sent a query with the checking-disabled (CD) bit set and
   the answer was NXDOMAIN, the resolver cached that unvalidated negative
   response and discarded any DNSSEC-validated records it already held
   for the same name, even though the validated data was more
   trustworthy. A single such response - including a forged one - could
   flush validated records from the cache and force the resolver to fetch
   them again. The resolver now checks the trust level of the existing
   data first and leaves the cache unchanged when it is already
   validated.

 - Fix a 'deny-answer-aliases' configuration bypass issue.

   It was possible to use a maliciously crafted authoritative zone to
   make :iscman:`named` resolver synthesize a ``DNAME`` "alias" that
   should have been rejected by the configured :any:`deny-answer-aliases`
   option. This has been fixed.

 - Reject external referrals from forwarders.

   Under `forward-first` policy in a forwarding zone BIND could accept NS
   above the forward zone apex from negative responses. This has been
   fixed.


 - Fix a zone transfer over TLS (XoT) issue when using the opportunistic
   TLS mode.

   The :iscman:`named` process, running as secondary DNS server,
   configured to transfer a zone from a primary server using an encrypted
   XoT transport in opportunistic TLS mode (i.e. without peer
   certificate/hostname validation) could terminate unexpectedly when the
   TLS ALPN negotiation with primary server was unsuccessful. This has
   been fixed.

 - Unvalidated opt-out NSEC3 could be accepted in insecurity proof.

   When determining whether an insecure delegation is legitimate, NSEC3
   opt-out records which had not yet passed validation could be used.
   This has been fixed.

 - Check wildcard signer and NOQNAME signer match.

   A positive wildcard answer, and the NSEC3 proof that the requested
   name doesn't exist in the zone, must both be from the same zone.
   Otherwise, an NSEC3 from an ancestor zone could be used to interfere
   with validation.

   We now retrieve the signer name from a wildcard response's signature.
   An NSEC3 record cannot be used as a NOQNAME proof for the wildcard
   unless it exactly matches the name one level above the NSEC3.

 - Require secure trust for covering NSEC in the RBT cache.

   The guard against synthesizing negative answers from a pending NSEC
   (#5977) was only added to the QP cache's find_coveringnsec(); the RBT
   cache database kept binding any covering NSEC regardless of trust.  On
   builds configured with --with-cachedb=rbt this lets a piggy-backed,
   unvalidated NSEC drive a synthesized NXDOMAIN, reviving the cache
   poisoning that was fixed for the default cache.

   query_coveringnsec() only verifies the covering NSEC's trust on its
   NODATA path; the NXDOMAIN path relies on the database returning a
   secure record.  Require the NSEC and its RRSIG to be dns_trust_secure
   in find_coveringnsec(), matching the QP cache.

 - Check dns_rdata_fromstruct() return values.

   In some functions implementing RFC 5011 key maintenance, the results
   of `dns_rdata_fromstruct()` were not checked. This has been fixed.

 - Fix CNAME resolution failure caused by a cached SERVFAIL response.

   Under certain circumstances, a cached SERVFAIL response could
   incorrectly prevent successful resolution of a CNAME target. This
   could cause resolution failures to persist until the cached SERVFAIL
   entry expired, even when the CNAME target itself was otherwise
   resolvable. This issue has been fixed.

 - [CVE-2026-13204] Prevent crash from malformed NSEC/NSEC3 response.

   An assertion could be triggered by an improperly signed NOQNAME proof.
   This has been fixed.

 - Reject unsupported RSA DNSKEY shapes during DNSSEC validation.

   An authoritative server publishing an RSA DNSKEY with an unusually
   large modulus or an exotic public exponent could make each DNSSEC
   signature check on a validating recursive resolver noticeably more
   expensive than for a normally sized key.  Such DNSKEYs are now treated
   as invalid.

 - Fix a bug in GeoIP2 string matching.

   When using GeoIP2 ACLs (see :any:`acl`), :iscman:`named` could
   incorrectly match a name using a sub-string instead of the full name
   match. This has been fixed.

 - Fix DNS-over-HTTPS (DoH) quota configuration issue.

   The :any:`http-listener-clients` and
   :any:`http-streams-per-connection` configuration options could be
   truncated to smaller values (or to ``0``, which means unlimited) when
   very big configuration values were used, which exceeded ``65535``. As
   a note - it is very unlikely that such big values are used in
   production, and the default values for the affected options are
   ``300`` and ``100``, correspondingly. This has been fixed.

 - Fix invalid pointer release in JSON statistics-channel response.

   Each response served on a JSON statistics endpoint released the wrong
   pointer to the JSON library after the response was sent: the response
   body string instead of the JSON document.  With the current responses
   this does not crash named in practice, but the call is incorrect and
   can in principle corrupt memory.  XML responses are not affected.

 - Truncated reply to a TSIG query no longer stalls the resolver.

   When an upstream server returned a truncated reply to a query that
   BIND had signed with TSIG, the resolver could keep waiting for a
   follow-up UDP packet that never arrived, so the query stalled until it
   hit resolver-query-timeout and the client received no answer. BIND now
   treats any reply it cannot authenticate as an immediate failure and
   returns SERVFAIL right away as a defense in depth.

 - Ignore updates removing DNSKEY RRset with class ANY.

   When a Dynamic Update is received that removes the ``DNSKEY`` (or
   ``CDNSKEY``, or ``CDS``) RRset, remove all records except the ones
   that are in use for signing for the zone.

 - Fix a memory leak when updating a zone with more than 32 DNSSEC keys.

   Applying changes to a signed zone — via DNS UPDATE or the
   inline-signing raw-to-secure sync — leaked the surplus keys when the
   zone's key directory held more than 32, slowly growing named's memory
   use.

 - Fix the memory ordering in the adaptive read-write lock.

   On hardware with a weak memory model, the internal read-write lock
   could briefly admit a reader and a writer at the same time, risking
   sporadic crashes or incorrect data. The reader/writer handshake now
   uses sequentially consistent ordering so the two can no longer
   overlap.

 - Print the full OID in PRIVATEOID key comments.

   The OID in the "; alg = ..." comment of a PRIVATEOID key was truncated
   to sixteen characters.

 - Correct locator decoding for NID, L64, and L32 records.

   NID, L64, and L32 records were decoded incorrectly when converted into
   their parsed structures, because the preference field was not skipped
   before the locator.

 - Fix a possible crash when cleaning up a view's caches.

   In rare cases named could crash while a view was being removed, for
   example during reconfiguration or shutdown, as its internal caches
   were torn down. This has been fixed.

 - Preserve the request message across async SIG(0) processing.

   For SIG(0)-signed requests, view matching is offloaded and the request
   is finished asynchronously from ns_client_request_continue(), which
   passes client->inner.buffer to dns_dt_send().  That buffer aliases the
   network manager's receive buffer, only valid during the read callback,
   so it may already be freed and reused, producing garbage dnstap frames
   (e.g. the "upforwd" sig0-over-DoT test fails with UQ=0).

   Copy the request message when entering async mode and reference the
   copy, freeing it in ns__client_reset_cb().

 - Ignore 0-byte reads in the TCP read callback. ``8588ffec7de``

   Callbacks for libuv stream reads do not signal zero-length reads as a
   failure signal but rather as EAGAIN/EWOULDBLOCK. This can trigger an
   assertion when a zero-length read is pushed onto a PROXYv2 endpoint
   that has not yet processed the headers as it expects a non-NULL region
   of positive length.

 - Include the IPv6 address's brackets in the parsed URL/URI host.

   The brackets are not included in the host component of the parsed
   URL/URI. Change the parser to include the brackets.

 - Improve the input validation of the isc_url_parse() function.

   The isc_url_parse() function failed to check the input buffer's length
   and assumed that it can't be bigger than UINT16_MAX, because both the
   'off' and 'len' fields of the 'isc_url_parser_t' structure are
   uint16_t.

   Add a check to not accept a buffer longer than 8192 octets.

 - Only print per zone glue stats when query statistics is full.

   The code printing query statistics was ignoring the zone-statistics
   option. This has been fixed.

 - CDS/CDNSKEY records were not removed when re-configuring the server.

   When on an ``rndc reconfig`` the DNSSEC policy changes such that it
   changes the expected ``CDNSKEY`` and/or ``CDS`` records in the zone,
   the RRset should be updated accordingly. This did not happen when
   removing digests from the configuration, or setting `cdnskey no;`.
   This has been fixed.

 - Fix a crash when querying an empty non-terminal in a wildcard zone in
   RBTDB.

   A query for an empty non-terminal in a wildcard zone served from the
   RBT zone database could abort named with an assertion failure.  It now
   returns the correct NODATA answer.

 - Stop reusing outgoing TCP connections the peer has already closed.

   ``named`` could hand a new query an idle forwarder/upstream TCP or TLS
   connection that the peer had already closed, causing the query to fail
   (and CLOSE-WAIT sockets to pile up). Idle reused connections are now
   watched, so a close is noticed and the connection is dropped instead
   of reused. A new ``tcp-reuse-timeout`` option controls how long an
   idle outgoing connection is kept open for reuse (default 5 seconds).

 - Fix DNSSEC validation failures for names under an apex DNAME.

   DNSSEC validation could fail with SERVFAIL for names covered by a
   DNAME at the apex of a signed zone, unless the zone's keys were
   already validated in the cache. This regression was introduced by the
   recent fix for resolver stalls on CNAME responses to DS queries.

 - Avoid needless queries when the DNSSEC validation limit is reached.

   A validating resolver could send one needless upstream query after
   reaching its per-fetch DNSSEC validation limit. It now stops
   immediately.

 - Avoid writing through a const pointer in render_xsl()

   render_xsl() served the static XSL stylesheet by casting away the
   const qualifier of xslmsg and handing the pointer to
   isc_buffer_reinit():

   p = UNCONST(xslmsg);     isc_buffer_reinit(b, p, strlen(xslmsg));

   isc_buffer_reinit() copies any pre-existing buffer content into the
   new base with memmove(), so the call would write into xslmsg, which is
   a 'const char[]' living in read-only memory.  This is safe today only
   because the supplied bodybuffer is always freshly initialized with
   length 0, so the memmove() never runs -- a fragile,
   action-at-a-distance invariant that GCC's -fanalyzer flags as a write
   to a const object (-Wanalyzer-write-to-const).

   Use isc_buffer_constinit(), the primitive intended for pointing a
   buffer at constant data: it goes through isc_buffer_init() and never
   writes to the base.  This drops the UNCONST cast, keeps xslmsg in
   read-only memory, and silences the analyzer warning.

 - Don't serve a stale CNAME or record when fresh data of the other
   exists.

   When a cached name held both a CNAME and records of another type — one
   stale, the other still fresh — named with serve-stale could return the
   expired set instead of the fresh one, in either direction. It now
   prefers whichever is fresh.

 - Fix compatibility with OpenSSL 1.0.2u.

   BIND failed to build with OpenSSL 1.0.2u. Add the missing header file
   includes.

 - Only update the global tid_count once.

   Skip updating the `tid_count` value on repeated calls to prevent
   ThreadSanitizer 'data race'.
-- 
Ticket URL: <https://wiki.linuxfromscratch.org/blfs/ticket/23637#comment:2>
BLFS Trac <https://wiki.linuxfromscratch.org/blfs/>
Beyond Linux From Scratch

-- 
http://lists.linuxfromscratch.org/sympa/info/blfs-book
Unsubscribe: See the above information page