diff --git a/CHANGES b/CHANGES index 443aefc743..c407e684b4 100644 --- a/CHANGES +++ b/CHANGES @@ -43,17 +43,32 @@ 5963. [bug] Ensure struct named_server is properly initialized. [GL #6531] -5962. [placeholder] + --- 9.19.5 released --- + +5962. [security] Fix memory leak in EdDSA verify processing. + (CVE-2022-38178) [GL #3487] 5961. [placeholder] -5960. [placeholder] +5960. [security] Fix serve-stale crash that could happen when + stale-answer-client-timeout was set to 0 and there was + a stale CNAME in the cache for an incoming query. + (CVE-2022-3080) [GL #3517] -5959. [placeholder] +5959. [security] Fix memory leaks in the DH code when using OpenSSL 3.0.0 + and later versions. The openssldh_compare(), + openssldh_paramcompare(), and openssldh_todns() + functions were affected. (CVE-2022-2906) [GL #3491] -5958. [placeholder] +5958. [security] When an HTTP connection was reused to get + statistics from the stats channel, and zlib + compression was in use, each successive + response sent larger and larger blocks of memory, + potentially reading past the end of the allocated + buffer. (CVE-2022-2881) [GL #3493] -5957. [placeholder] +5957. [security] Prevent excessive resource use while processing large + delegations. (CVE-2022-2795) [GL #3394] 5956. [func] Make RRL code treat all QNAMEs that are subject to wildcard processing within a given zone as the same diff --git a/doc/arm/notes.rst b/doc/arm/notes.rst index c29c9f5552..ab28b4955c 100644 --- a/doc/arm/notes.rst +++ b/doc/arm/notes.rst @@ -37,6 +37,7 @@ https://www.isc.org/download/. There you will find additional information about each release, and source code. .. include:: ../notes/notes-current.rst +.. include:: ../notes/notes-9.19.5.rst .. include:: ../notes/notes-9.19.4.rst .. include:: ../notes/notes-9.19.3.rst .. include:: ../notes/notes-9.19.2.rst diff --git a/doc/notes/notes-9.19.5.rst b/doc/notes/notes-9.19.5.rst new file mode 100644 index 0000000000..b9a539b555 --- /dev/null +++ b/doc/notes/notes-9.19.5.rst @@ -0,0 +1,86 @@ +.. 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.19.5 +--------------------- + +Security Fixes +~~~~~~~~~~~~~~ + +- Previously, there was no limit to the number of database lookups + performed while processing large delegations, which could be abused to + severely impact the performance of :iscman:`named` running as a + recursive resolver. This has been fixed. (CVE-2022-2795) + + ISC would like to thank Yehuda Afek from Tel-Aviv University and Anat + Bremler-Barr & Shani Stajnrod from Reichman University for bringing + this vulnerability to our attention. :gl:`#3394` + +- When an HTTP connection was reused to request statistics from the + stats channel, the content length of successive responses could grow + in size past the end of the allocated buffer. This has been fixed. + (CVE-2022-2881) :gl:`#3493` + +- Memory leaks in code handling Diffie-Hellman (DH) keys were fixed that + could be externally triggered, when using TKEY records in DH mode with + OpenSSL 3.0.0 and later versions. (CVE-2022-2906) :gl:`#3491` + +- :iscman:`named` running as a resolver with the + :any:`stale-answer-client-timeout` option set to ``0`` could crash + with an assertion failure, when there was a stale CNAME in the cache + for the incoming query. This has been fixed. (CVE-2022-3080) + :gl:`#3517` + +- Memory leaks were fixed that could be externally triggered in the + DNSSEC verification code for the EdDSA algorithm. (CVE-2022-38178) + :gl:`#3487` + +New Features +~~~~~~~~~~~~ + +- A new Response Policy Zone (RPZ) :ref:`option`, ``ede``, was + added. It enables an :rfc:`8914` Extended DNS Error (EDE) code of + choice to be set for responses which have been modified by a given + RPZ. :gl:`#3410` + +- Worker threads' event loops are now managed by a new "loop manager" + API, significantly changing the architecture of the task, timer, and + networking subsystems for improved performance and code flow. + :gl:`#3508` + +Feature Changes +~~~~~~~~~~~~~~~ + +- Response Rate Limiting (RRL) code now treats all QNAMEs that are + subject to wildcard processing within a given zone as the same name, + to prevent circumventing the limits enforced by RRL. :gl:`#3459` + +- Zones using :any:`dnssec-policy` now require dynamic DNS or + :any:`inline-signing` to be configured explicitly. :gl:`#3381` + +- When reconfiguring :any:`dnssec-policy` from using NSEC with an + NSEC-only DNSKEY algorithm (e.g. RSASHA1) to a policy that uses NSEC3, + BIND 9 no longer fails to sign the zone; instead, it keeps using NSEC + until the offending DNSKEY records have been removed from the zone, + then switches to using NSEC3. :gl:`#3486` + +- A backward-compatible approach was implemented for encoding + internationalized domain names (IDN) in :iscman:`dig` and converting + the domain to IDNA2008 form; if that fails, BIND tries an IDNA2003 + conversion. :gl:`#3485` + +Bug Fixes +~~~~~~~~~ + +- A serve-stale bug was fixed, where BIND would try to return stale data + from cache for lookups that received duplicate queries or queries that + would be dropped. This bug resulted in premature SERVFAIL responses, + and has now been resolved. :gl:`#2982` diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c index e76cfbe310..f063160148 100644 --- a/lib/dns/openssldh_link.c +++ b/lib/dns/openssldh_link.c @@ -165,6 +165,7 @@ openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, static bool openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { + bool ret = true; #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh1, *dh2; const BIGNUM *pub_key1 = NULL, *pub_key2 = NULL; @@ -214,18 +215,17 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0 || BN_cmp(pub_key1, pub_key2) != 0) { - return (false); + DST_RET(false); } if (priv_key1 != NULL || priv_key2 != NULL) { - if (priv_key1 == NULL || priv_key2 == NULL) { - return (false); - } - if (BN_cmp(priv_key1, priv_key2) != 0) { - return (false); + if (priv_key1 == NULL || priv_key2 == NULL || + BN_cmp(priv_key1, priv_key2) != 0) { + DST_RET(false); } } +err: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (p1 != NULL) { BN_free(p1); @@ -253,11 +253,12 @@ openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - return (true); + return (ret); } static bool openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { + bool ret = true; #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh1, *dh2; const BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL; @@ -295,9 +296,10 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0) { - return (false); + DST_RET(false); } +err: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (p1 != NULL) { BN_free(p1); @@ -313,7 +315,7 @@ openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - return (true); + return (ret); } #if OPENSSL_VERSION_NUMBER < 0x30000000L @@ -672,6 +674,7 @@ uint16_fromregion(isc_region_t *region) { static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { + isc_result_t ret = ISC_R_SUCCESS; #if OPENSSL_VERSION_NUMBER < 0x30000000L DH *dh; const BIGNUM *pub_key = NULL, *p = NULL, *g = NULL; @@ -713,7 +716,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { publen = BN_num_bytes(pub_key); dnslen = plen + glen + publen + 6; if (r.length < (unsigned int)dnslen) { - return (ISC_R_NOSPACE); + DST_RET(ISC_R_NOSPACE); } uint16_toregion(plen, &r); @@ -742,6 +745,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { isc_buffer_add(data, dnslen); +err: #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (p != NULL) { BN_free(p); @@ -754,7 +758,7 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - return (ISC_R_SUCCESS); + return (ret); } static isc_result_t diff --git a/lib/dns/openssleddsa_link.c b/lib/dns/openssleddsa_link.c index 2f599647da..fa8d51b1ef 100644 --- a/lib/dns/openssleddsa_link.c +++ b/lib/dns/openssleddsa_link.c @@ -234,11 +234,11 @@ openssleddsa_verify(dst_context_t *dctx, const isc_region_t *sig) { } #endif /* if HAVE_OPENSSL_ED448 */ if (siglen == 0) { - return (ISC_R_NOTIMPLEMENTED); + DST_RET(ISC_R_NOTIMPLEMENTED); } if (sig->length != siglen) { - return (DST_R_VERIFYFAILURE); + DST_RET(DST_R_VERIFYFAILURE); } isc_buffer_usedregion(buf, &tbsreg); diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 8825948287..ff8f264c6f 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -214,6 +214,17 @@ */ #define NS_FAIL_LIMIT 4 #define NS_RR_LIMIT 5 +/* + * IP address lookups are performed for at most NS_PROCESSING_LIMIT NS RRs in + * any NS RRset encountered, to avoid excessive resource use while processing + * large delegations. + */ +#define NS_PROCESSING_LIMIT 20 + +STATIC_ASSERT(NS_PROCESSING_LIMIT > NS_RR_LIMIT, + "The maximum number of NS RRs processed for each delegation " + "(NS_PROCESSING_LIMIT) must be larger than the large delegation " + "threshold (NS_RR_LIMIT)."); /* Hash table for zone counters */ #ifndef RES_DOMAIN_HASH_BITS @@ -3536,6 +3547,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) { bool need_alternate = false; bool all_spilled = true; unsigned int no_addresses = 0; + unsigned int ns_processed = 0; FCTXTRACE5("getaddresses", "fctx->depth=", fctx->depth); @@ -3726,6 +3738,11 @@ normal_nses: dns_rdata_reset(&rdata); dns_rdata_freestruct(&ns); + + if (++ns_processed >= NS_PROCESSING_LIMIT) { + result = ISC_R_NOMORE; + break; + } } if (result != ISC_R_NOMORE) { return (result); diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index ac31b9a23c..183cb203c6 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -202,6 +202,8 @@ free_buffer(isc_mem_t *mctx, isc_buffer_t *buffer) { if (r.base != NULL) { isc_mem_put(mctx, r.base, r.length); } + + isc_buffer_initnull(buffer); } isc_result_t @@ -864,6 +866,7 @@ httpd_compress(isc_httpd_t *httpd) { inputlen = isc_buffer_usedlength(&httpd->bodybuffer); alloc_compspace(httpd, inputlen); + isc_buffer_clear(&httpd->compbuffer); isc_buffer_region(&httpd->compbuffer, &r); /* diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index 843de665ea..c1c7b5e430 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -203,6 +203,7 @@ struct query_ctx { bool authoritative; /* authoritative query? */ bool want_restart; /* CNAME chain or other * restart needed */ + bool refresh_rrset; /* stale RRset refresh needed */ bool need_wildcardproof; /* wildcard proof needed */ bool nxrewrite; /* negative answer from RPZ */ bool findcoveringnsec; /* lookup covering NSEC */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 46ef30e515..ebdd73ee31 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -5792,7 +5792,6 @@ query_lookup(query_ctx_t *qctx) { bool dbfind_stale = false; bool stale_timeout = false; bool stale_found = false; - bool refresh_rrset = false; bool stale_refresh_window = false; uint16_t ede = 0; @@ -5992,8 +5991,7 @@ query_lookup(query_ctx_t *qctx) { "%s stale answer used, an attempt to " "refresh the RRset will still be made", namebuf); - refresh_rrset = STALE(qctx->rdataset); - qctx->client->nodetach = refresh_rrset; + qctx->refresh_rrset = STALE(qctx->rdataset); ns_client_extendederror( qctx->client, ede, "stale data prioritized over lookup"); @@ -6037,17 +6035,6 @@ query_lookup(query_ctx_t *qctx) { result = query_gotanswer(qctx, result); - if (refresh_rrset) { - /* - * If we reached this point then it means that we have found a - * stale RRset entry in cache and BIND is configured to allow - * queries to be answered with stale data if no active RRset - * is available, i.e. "stale-anwer-client-timeout 0". But, we - * still need to refresh the RRset. - */ - query_refresh_rrset(qctx); - } - cleanup: return (result); } @@ -7999,11 +7986,14 @@ query_addanswer(query_ctx_t *qctx) { /* * On normal lookups, clear any rdatasets that were added on a - * lookup due to stale-answer-client-timeout. + * lookup due to stale-answer-client-timeout. Do not clear if we + * are going to refresh the RRset, because the stale contents are + * prioritized. */ if (QUERY_STALEOK(&qctx->client->query) && - !QUERY_STALETIMEOUT(&qctx->client->query)) + !QUERY_STALETIMEOUT(&qctx->client->query) && !qctx->refresh_rrset) { + CCTRACE(ISC_LOG_DEBUG(3), "query_clear_stale"); query_clear_stale(qctx->client); /* * We can clear the attribute to prevent redundant clearing @@ -11535,9 +11525,29 @@ ns_query_done(query_ctx_t *qctx) { /* * Client may have been detached after query_send(), so * we test and store the flag state here, for safety. + * If we are refreshing the RRSet, we must not detach from the client + * in the query_send(), so we need to override the flag. */ + if (qctx->refresh_rrset) { + qctx->client->nodetach = true; + } nodetach = qctx->client->nodetach; query_send(qctx->client); + + if (qctx->refresh_rrset) { + /* + * If we reached this point then it means that we have found a + * stale RRset entry in cache and BIND is configured to allow + * queries to be answered with stale data if no active RRset + * is available, i.e. "stale-anwer-client-timeout 0". But, we + * still need to refresh the RRset. To prevent adding duplicate + * RRsets, clear the RRsets from the message before doing the + * refresh. + */ + message_clearrdataset(qctx->client->message, 0); + query_refresh_rrset(qctx); + } + if (!nodetach) { qctx->detach_client = true; }