diff --git a/doc/arm/changelog.rst b/doc/arm/changelog.rst index 6723be7e21..e37b8f37d6 100644 --- a/doc/arm/changelog.rst +++ b/doc/arm/changelog.rst @@ -18,6 +18,7 @@ Changelog development. Regular users should refer to :ref:`Release Notes ` for changes relevant to them. +.. include:: ../changelog/changelog-9.21.8.rst .. include:: ../changelog/changelog-9.21.7.rst .. include:: ../changelog/changelog-9.21.6.rst .. include:: ../changelog/changelog-9.21.5.rst diff --git a/doc/arm/notes.rst b/doc/arm/notes.rst index eaaf5c4443..501b7bd386 100644 --- a/doc/arm/notes.rst +++ b/doc/arm/notes.rst @@ -47,6 +47,7 @@ The list of known issues affecting the latest version in the 9.21 branch can be found at https://gitlab.isc.org/isc-projects/bind9/-/wikis/Known-Issues-in-BIND-9.21 +.. include:: ../notes/notes-9.21.8.rst .. include:: ../notes/notes-9.21.7.rst .. include:: ../notes/notes-9.21.6.rst .. include:: ../notes/notes-9.21.5.rst diff --git a/doc/changelog/changelog-9.21.8.rst b/doc/changelog/changelog-9.21.8.rst new file mode 100644 index 0000000000..fe99bded60 --- /dev/null +++ b/doc/changelog/changelog-9.21.8.rst @@ -0,0 +1,170 @@ +.. 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. + +BIND 9.21.8 +----------- + +Security Fixes +~~~~~~~~~~~~~~ + +- [CVE-2025-40775] Prevent assertion when processing TSIG algorithm. + ``1665e05438a`` + + DNS messages that included a Transaction Signature (TSIG) containing + an invalid value in the algorithm field caused :iscman:`named` to + crash with an assertion failure. This has been fixed. + :cve:`2025-40775` :gl:`#5300` + +New Features +~~~~~~~~~~~~ + +- Implement tcp-primaries-timeout. ``2054186f408`` + + The new `tcp-primaries-timeout` configuration option works the same + way as the older `tcp-initial-timeout` option, but applies only to the + TCP connections made to the primary servers, so that the timeout value + can be set separately for them. By default, it's set to 150, which is + 15 seconds. :gl:`#3649` :gl:`!9376` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Use jinja2 templates in system tests. ``dfe755a5d6f`` + + `python-jinja2` is now required to run system tests. :gl:`#4938` + :gl:`!9588` + +- Reduce QPDB_VIRTUAL to 10 seconds. ``ed8421f405a`` + + The QPDB_VIRTUAL value was introduced to allow the clients (presumably + ns_clients) that has been running for some time to access the cached + data that was valid at the time of its inception. The default value + of 5 minutes is way longer than longevity of the ns_client object as + the resolver will give up after 2 minutes. + + Reduce the value to 10 seconds to accomodate to honour the original + more closely, but still allow some leeway for clients that started + some time in the past. + + Our measurements show that even setting this value to 0 has no + statistically significant effect, thus the value of 10 seconds should + be on the safe side. :gl:`!10309` + +Bug Fixes +~~~~~~~~~ + +- Fix EDNS yaml output. ``6285cc3476c`` + + `dig` was producing invalid YAML when displaying some EDNS options. + This has been corrected. + + Several other improvements have been made to the display of EDNS + option data: - We now use the correct name for the UPDATE-LEASE + option, which was previously displayed as "UL", and split it into + separate LEASE and LEASE-KEY components in YAML mode. - Human-readable + durations are now displayed as comments in YAML mode so as not to + interfere with machine parsing. - KEY-TAG options are now displayed as + an array of integers in YAML mode. - EDNS COOKIE options are displayed + as separate CLIENT and SERVER components, and cookie STATUS is a + retrievable variable in YAML mode. :gl:`#5014` :gl:`!9695` + +- Return DNS COOKIE and NSID with BADVERS. ``79c50d45384`` + + This change allows the client to identify the server that returns the + BADVERS and to provide a DNS SERVER COOKIE to be included in the + resend of the request. :gl:`#5235` :gl:`!10334` + +- Disable own memory context for libxml2 on macOS. ``6f3fea837f0`` + + Apple broke custom memory allocation functions in the system-wide + libxml2 starting with macOS Sequoia 15.4. Usage of the custom memory + allocation functions has been disabled on macOS. :gl:`#5268` + :gl:`!10374` + +- `check_private` failed to account for the length byte before the OID. + ``ecbae71fe9a`` + + In PRIVATEOID keys, the key data begins with a length byte followed + by an ASN.1 object identifier that indicates the cryptographic + algorithm to use. Previously, the length byte was not accounted for + when checking the contents of keys and signatures, which could have + led to interoperability problems with any zones signed using + PRIVATEOID. This has been fixed. :gl:`#5270` :gl:`!10372` + +- Fix a serve-stale issue with a delegated zone. ``58a0e6cc614`` + + When ``stale-answer-client-timeout 0`` option was enabled, it could be + ignored when resolving a zone which is a delegation of an + authoritative zone belonging to the resolver. This has been fixed. + :gl:`#5275` :gl:`!10381` + +- Move the call_rcu_thread explicit create and shutdown to isc_loop. + ``e373f4062fe`` + + When isc__thread_initialize() is called from a library constructor, it + could be called before we fork the main process. This happens with + named, and then we have the call_rcu_thread attached to the pre-fork + process and not the post-fork process, which means that the initial + process will never shutdown, because there's noone to tell it so. + + Move the isc__thread_initialize() and isc__thread_shutdown() to the + isc_loop unit where we call it before creating the extra thread and + after joining all the extra threads respectively. :gl:`#5281` + :gl:`!10394` + +- Fix a date race in qpcache_addrdataset() ``47ccf613eb0`` + + The 'qpnode->nsec' structure member isn't protected by a lock and + there's a data race between the reading and writing parts in the + qpcache_addrdataset() function. Use a node read lock for accessing + 'qpnode->nsec' in qpcache_addrdataset(). Add an additional + 'qpnode->nsec != DNS_DB_NSEC_HAS_NSEC' check under a write lock to be + sure that no other competing thread changed it in the time when the + read lock is unlocked and a write lock is not acquired yet. + :gl:`#5285` :gl:`!10397` + +- Fix the ksr two-tone test. ``405f8a7bd85`` + + The two-tone ksr subtest (test_ksr_twotone) depended on the + dnssec-policy keys algorithm values in named.conf being entered in + numerical order. As the algorithms used in the test can be selected + randomly this does not always happen. Sort the dnssec-policy keys by + algorithm when adding them to the key list from named.conf. + :gl:`#5286` :gl:`!10395` + +- Return the correct NSEC3 records for NXDOMAIN responses. + ``1ec15358278`` + + The wrong NSEC3 records were sometimes returned as proof that the + QNAME did not exist. This has been fixed. :gl:`#5292` :gl:`!10447` + +- Call rcu_barrier earlier in the destructor. ``962b75dca46`` + + If a call_rcu thread is running, there is a possible race condition + where the destructors run before all call_rcu callbacks have finished + running. This can happen, for example, if the call_rcu callback tries + to log something after the logging context has been torn down. + + In !10394, we tried to counter this by explicitely creating a call_rcu + thread an shutting it down before running the destructors, but it is + possible for things to "slip" and end up on the default call_rcu + thread. + + As a quickfix, this commit moves an rcu_barrier() that was in the mem + context destructor earlier, so that it "protects" all libisc + destructors. :gl:`#5296` :gl:`!10423` + +- Fix the error handling of put_yamlstr calls. ``fad97e3cd11`` + + The return value was sometimes being ignored when it shouldn't have + been. :gl:`#5301` :gl:`!10432` + + diff --git a/doc/notes/notes-9.21.8.rst b/doc/notes/notes-9.21.8.rst new file mode 100644 index 0000000000..b30ec38acc --- /dev/null +++ b/doc/notes/notes-9.21.8.rst @@ -0,0 +1,105 @@ +.. 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. + +Notes for BIND 9.21.8 +--------------------- + +Security Fixes +~~~~~~~~~~~~~~ + +- Prevent an assertion failure when processing TSIG algorithm. + + DNS messages that included a Transaction Signature (TSIG) containing + an invalid value in the algorithm field caused :iscman:`named` to + crash with an assertion failure. This has been fixed. + :cve:`2025-40775` :gl:`#5300` + +New Features +~~~~~~~~~~~~ + +- Implement configurable TCP timeouts for zone refresh queries. + + The new :any:`tcp-primaries-timeout` configuration option works the + same way as the older :any:`tcp-initial-timeout` option but applies + only to the TCP connections made to the primary servers, so that the + timeout value can be set separately for them. The default is + 150 (15 seconds). :gl:`#3649` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Return DNS COOKIE and NSID with BADVERS. + + This change allows the client to identify a server that returns a + BADVERS response and to provide a DNS SERVER COOKIE to be included in + the resent request. :gl:`#5235` + +- Disable separate memory context for libxml2 memory allocations on + macOS. + + As of macOS Sequoia 15.4, custom memory allocation functions are no + longer supported by the system-wide version of libxml2. This prevents + tracking libxml2 memory allocations in a separate :iscman:`named` + memory context, so the latter has been disabled on macOS; the system + allocator is now directly used for libxml2 memory allocations on that + operating system. :gl:`#5268` + +- Use Jinja2 templates in system tests. + + `python-jinja2` is now required to run system tests. :gl:`#4938` + +Bug Fixes +~~~~~~~~~ + +- Return the correct NSEC3 records for NXDOMAIN responses. + + The wrong NSEC3 records were sometimes returned as proof that the + QNAME did not exist. This has been fixed. :gl:`#5292` + +- Fix EDNS YAML output in :iscman:`dig`. + + :iscman:`dig` was producing invalid YAML when displaying some EDNS + options. This has been corrected. + + Several other improvements have been made to the display of EDNS + option data: + + - The correct name is now used for the UPDATE-LEASE option, which + was previously displayed as ``UL``, and it is split into separate + ``LEASE`` and ``LEASE-KEY`` components in YAML mode. + + - Human-readable durations are now displayed as comments in YAML + mode so as not to interfere with machine parsing. + + - KEY-TAG options are now displayed as an array of integers in YAML + mode. + + - EDNS COOKIE options are displayed as separate ``CLIENT`` and + ``SERVER`` components, and cookie STATUS is a retrievable variable + in YAML mode. + + :gl:`#5014` + +- Fix RDATA checks for PRIVATEOID keys. + + In PRIVATEOID keys, the key data begins with a length byte followed by + an ASN.1 object identifier that indicates the cryptographic algorithm + to use. Previously, the length byte was not accounted for when + checking the contents of keys and signatures, which could have led to + interoperability problems with any zones signed using PRIVATEOID. This + has been fixed. :gl:`#5270` + +- Fix a serve-stale issue with a delegated zone. + + Even with :any:`stale-answer-client-timeout` set to ``0``, stale + responses were not returned immediately for names in domains delegated + from authoritative zones configured on the resolver. This has been + fixed. :gl:`#5275` diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 81458aa68c..7ba445a1e4 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -285,18 +285,16 @@ struct dns_message { ISC_LIST(dns_rdata_t) freerdata; ISC_LIST(dns_rdatalist_t) freerdatalist; - dns_rcode_t tsigstatus; - dns_rcode_t querytsigstatus; - dns_name_t *tsigname; /* Owner name of TSIG, if any - * */ + dns_rcode_t tsigstatus; + dns_rcode_t querytsigstatus; + dns_name_t *tsigname; /* Owner name of TSIG, if any */ dns_rdataset_t *querytsig; dns_tsigkey_t *tsigkey; dst_context_t *tsigctx; int sigstart; int timeadjust; - dns_name_t *sig0name; /* Owner name of SIG0, if any - * */ + dns_name_t *sig0name; /* Owner name of SIG0, if any */ dst_key_t *sig0key; dns_rcode_t sig0status; isc_region_t query; diff --git a/lib/dns/include/dns/tsig.h b/lib/dns/include/dns/tsig.h index 5b4e17d90e..6ad65904b7 100644 --- a/lib/dns/include/dns/tsig.h +++ b/lib/dns/include/dns/tsig.h @@ -78,12 +78,14 @@ struct dns_tsigkeyring { struct dns_tsigkey { /* Unlocked */ - unsigned int magic; /*%< Magic number. */ - isc_mem_t *mctx; - dst_key_t *key; /*%< Key */ - dns_fixedname_t fn; - dns_name_t *name; /*%< Key name */ - const dns_name_t *algorithm; /*%< Algorithm name */ + unsigned int magic; /*%< Magic number. */ + isc_mem_t *mctx; + dst_key_t *key; /*%< Key */ + dns_fixedname_t fn; + dns_name_t *name; /*%< Key name */ + dst_algorithm_t alg; /*< Algorithm */ + dns_name_t algname; /*< Algorithm name, only used if + algorithm is DST_ALG_UNKNOWN */ dns_name_t *creator; /*%< name that created secret */ bool generated : 1; /*%< key was auto-generated */ bool restored : 1; /*%< key was restored at startup */ @@ -234,6 +236,16 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkeyp, const dns_name_t *name, *\li #ISC_R_NOTFOUND */ +const dns_name_t * +dns_tsigkey_algorithm(dns_tsigkey_t *tkey); +/*%< + * Returns the key algorithm associated with a tsigkey object. + * + * Note that when a tsigkey object is created with algorithm + * DST_ALG_UNKNOWN, the unknown algorithm's name must be cloned + * into tsigkey->algname. + */ + void dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp); /*%< diff --git a/lib/dns/message.c b/lib/dns/message.c index 9eaeb990f0..8d573d65e6 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -633,12 +633,11 @@ msgreset(dns_message_t *msg, bool everything) { static unsigned int spacefortsig(dns_tsigkey_t *key, int otherlen) { - isc_region_t r1, r2; - unsigned int x; - isc_result_t result; + isc_region_t r1 = { 0 }, r2 = { 0 }; + unsigned int x = 0; /* - * The space required for an TSIG record is: + * The space required for a TSIG record is: * * n1 bytes for the name * 2 bytes for the type @@ -659,11 +658,11 @@ spacefortsig(dns_tsigkey_t *key, int otherlen) { */ dns_name_toregion(key->name, &r1); - dns_name_toregion(key->algorithm, &r2); - if (key->key == NULL) { - x = 0; - } else { - result = dst_key_sigsize(key->key, &x); + if (key->alg != DST_ALG_UNKNOWN) { + dns_name_toregion(dns_tsigkey_algorithm(key), &r2); + } + if (key->key != NULL) { + isc_result_t result = dst_key_sigsize(key->key, &x); if (result != ISC_R_SUCCESS) { x = 0; } diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c index 88a6cdfd76..376bde418f 100644 --- a/lib/dns/tsig.c +++ b/lib/dns/tsig.c @@ -189,28 +189,6 @@ adjust_lru(dns_tsigkey_t *tkey) { } } -static const dns_name_t * -namefromalg(dst_algorithm_t alg) { - switch (alg) { - case DST_ALG_HMACMD5: - return dns_tsig_hmacmd5_name; - case DST_ALG_HMACSHA1: - return dns_tsig_hmacsha1_name; - case DST_ALG_HMACSHA224: - return dns_tsig_hmacsha224_name; - case DST_ALG_HMACSHA256: - return dns_tsig_hmacsha256_name; - case DST_ALG_HMACSHA384: - return dns_tsig_hmacsha384_name; - case DST_ALG_HMACSHA512: - return dns_tsig_hmacsha512_name; - case DST_ALG_GSSAPI: - return dns_tsig_gssapi_name; - default: - return NULL; - } -} - isc_result_t dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm, dst_key_t *dstkey, bool generated, bool restored, @@ -230,6 +208,8 @@ dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm, .restored = restored, .inception = inception, .expire = expire, + .alg = algorithm, + .algname = DNS_NAME_INITEMPTY, .link = ISC_LINK_INITIALIZER, }; @@ -247,8 +227,6 @@ dns_tsigkey_createfromkey(const dns_name_t *name, dst_algorithm_t algorithm, goto cleanup_name; } - tkey->algorithm = namefromalg(algorithm); - if (creator != NULL) { tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t)); dns_name_init(tkey->creator); @@ -432,7 +410,8 @@ dump_key(dns_tsigkey_t *tkey, FILE *fp) { dns_name_format(tkey->name, namestr, sizeof(namestr)); dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr)); - dns_name_format(tkey->algorithm, algorithmstr, sizeof(algorithmstr)); + dns_name_format(dns_tsigkey_algorithm(tkey), algorithmstr, + sizeof(algorithmstr)); result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length); if (result == ISC_R_SUCCESS) { fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr, @@ -605,7 +584,7 @@ dns_tsig_sign(dns_message_t *msg) { }; dns_name_init(&tsig.algorithm); - dns_name_clone(key->algorithm, &tsig.algorithm); + dns_name_clone(dns_tsigkey_algorithm(key), &tsig.algorithm); isc_buffer_init(&databuf, data, sizeof(data)); @@ -962,12 +941,17 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, } if (result != ISC_R_SUCCESS) { msg->tsigstatus = dns_tsigerror_badkey; - result = dns_tsigkey_create( - keyname, dns__tsig_algfromname(&tsig.algorithm), - NULL, 0, mctx, &msg->tsigkey); + alg = dns__tsig_algfromname(&tsig.algorithm); + result = dns_tsigkey_create(keyname, alg, NULL, 0, mctx, + &msg->tsigkey); if (result != ISC_R_SUCCESS) { return result; } + if (alg == DST_ALG_UNKNOWN) { + dns_name_clone(&tsig.algorithm, + &msg->tsigkey->algname); + } + tsig_log(msg->tsigkey, 2, "unknown key"); return DNS_R_TSIGVERIFYFAILURE; } @@ -1091,7 +1075,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, /* * Digest the key algorithm. */ - dns_name_toregion(tsigkey->algorithm, &r); + dns_name_toregion(dns_tsigkey_algorithm(tsigkey), &r); result = dst_context_adddata(ctx, &r); if (result != ISC_R_SUCCESS) { goto cleanup_context; @@ -1539,7 +1523,8 @@ again: RWUNLOCK(&ring->lock, locktype); return result; } - if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) { + + if (algorithm != NULL && key->alg != dns__tsig_algfromname(algorithm)) { RWUNLOCK(&ring->lock, locktype); return ISC_R_NOTFOUND; } @@ -1565,6 +1550,39 @@ again: return ISC_R_SUCCESS; } +const dns_name_t * +dns_tsigkey_algorithm(dns_tsigkey_t *tkey) { + REQUIRE(VALID_TSIGKEY(tkey)); + + switch (tkey->alg) { + case DST_ALG_HMACMD5: + return dns_tsig_hmacmd5_name; + case DST_ALG_HMACSHA1: + return dns_tsig_hmacsha1_name; + case DST_ALG_HMACSHA224: + return dns_tsig_hmacsha224_name; + case DST_ALG_HMACSHA256: + return dns_tsig_hmacsha256_name; + case DST_ALG_HMACSHA384: + return dns_tsig_hmacsha384_name; + case DST_ALG_HMACSHA512: + return dns_tsig_hmacsha512_name; + case DST_ALG_GSSAPI: + return dns_tsig_gssapi_name; + + case DST_ALG_UNKNOWN: + /* + * If the tsigkey object was created with an + * unknown algorithm, then we cloned + * the algorithm name here. + */ + return &tkey->algname; + + default: + UNREACHABLE(); + } +} + void dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsigkeyring_t **ringp) { dns_tsigkeyring_t *ring = NULL; diff --git a/tests/dns/tsig_test.c b/tests/dns/tsig_test.c index ee9ce6d4bb..b2c9bd980e 100644 --- a/tests/dns/tsig_test.c +++ b/tests/dns/tsig_test.c @@ -96,7 +96,7 @@ add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target, tsig.common.rdtype = dns_rdatatype_tsig; ISC_LINK_INIT(&tsig.common, link); dns_name_init(&tsig.algorithm); - dns_name_clone(key->algorithm, &tsig.algorithm); + dns_name_clone(dns_tsigkey_algorithm(key), &tsig.algorithm); tsig.timesigned = now; tsig.fudge = DNS_TSIG_FUDGE;