diff --git a/SOURCES/bind-9.16-CVE-2022-3094-1.patch b/SOURCES/bind-9.16-CVE-2022-3094-1.patch new file mode 100644 index 0000000..3a3e9c0 --- /dev/null +++ b/SOURCES/bind-9.16-CVE-2022-3094-1.patch @@ -0,0 +1,240 @@ +From 128b3b676eb9413b4d25fb29c560895cfbbfa92e Mon Sep 17 00:00:00 2001 +From: Evan Hunt +Date: Thu, 1 Sep 2022 16:05:04 -0700 +Subject: [PATCH] add an update quota + +limit the number of simultaneous DNS UPDATE events that can be +processed by adding a quota for update and update forwarding. +this quota currently, arbitrarily, defaults to 100. + +also add a statistics counter to record when the update quota +has been exceeded. + +(cherry picked from commit 7c47254a140c3e9cf383cda73c7b6a55c4782826) +--- + bin/named/bind9.xsl | 2 +- + bin/named/bind9.xsl.h | 8 +++++++- + bin/named/include/named/server.h | 7 ++++++- + bin/named/server.c | 3 +++ + bin/named/statschannel.c | 5 +++-- + bin/named/update.c | 34 +++++++++++++++++++++++++++++++- + doc/arm/Bv9ARM-book.xml | 15 ++++++++++++++ + 7 files changed, 68 insertions(+), 6 deletions(-) + +diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl +index 9a1c6ff..85fd4c4 100644 +--- a/bin/named/bind9.xsl ++++ b/bin/named/bind9.xsl +@@ -12,7 +12,7 @@ + + + +- ++ + + + +diff --git a/bin/named/bind9.xsl.h b/bin/named/bind9.xsl.h +index 9ce8cd7..5e0a892 100644 +--- a/bin/named/bind9.xsl.h ++++ b/bin/named/bind9.xsl.h +@@ -17,7 +17,13 @@ static char xslmsg[] = + "\n" + "\n" + " \n" +- " \n" ++#if 0 ++ " \n" ++ " \n" ++#endif ++ " \n" + " \n" + " \n" + " \n" +diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h +index 08a02dc..259acc7 100644 +--- a/bin/named/include/named/server.h ++++ b/bin/named/include/named/server.h +@@ -137,6 +137,9 @@ struct ns_server { + + uint16_t transfer_tcp_message_size; + isc_rng_t * rngctx; ++ ++/* CVE-2022-3094 */ ++ isc_quota_t updquota; + }; + + struct ns_altsecret { +@@ -230,7 +233,9 @@ enum { + dns_nsstatscounter_trystale = 59, + dns_nsstatscounter_usedstale = 60, + +- dns_nsstatscounter_max = 61 ++ dns_nsstatscounter_updatequota = 61, ++ ++ dns_nsstatscounter_max = 62 + }; + + /*% +diff --git a/bin/named/server.c b/bin/named/server.c +index 2d2fa0e..f09b895 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -9143,6 +9143,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = isc_quota_init(&server->recursionquota, 100); + RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ result = isc_quota_init(&server->updquota, 100); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); + + result = dns_aclenv_init(mctx, &server->aclenv); + RUNTIME_CHECK(result == ISC_R_SUCCESS); +@@ -9410,6 +9412,7 @@ ns_server_destroy(ns_server_t **serverp) { + + dns_aclenv_destroy(&server->aclenv); + ++ isc_quota_destroy(&server->updquota); + isc_quota_destroy(&server->recursionquota); + isc_quota_destroy(&server->tcpquota); + isc_quota_destroy(&server->xfroutquota); +diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c +index 56a9c21..1e8723c 100644 +--- a/bin/named/statschannel.c ++++ b/bin/named/statschannel.c +@@ -300,6 +300,7 @@ init_desc(void) { + SET_NSSTATDESC(reclimitdropped, + "queries dropped due to recursive client limit", + "RecLimitDropped"); ++ SET_NSSTATDESC(updatequota, "Update quota exceeded", "UpdateQuota"); + SET_NSSTATDESC(trystale, + "attempts to use stale cache data after lookup failure", + "QryTryStale"); +@@ -1546,7 +1547,7 @@ generatexml(ns_server_t *server, uint32_t flags, + ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\"")); + TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics")); + TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version", +- ISC_XMLCHAR "3.8")); ++ ISC_XMLCHAR "3.8.1")); + + /* Set common fields for statistics dump */ + dumparg.type = isc_statsformat_xml; +@@ -2303,7 +2304,7 @@ generatejson(ns_server_t *server, size_t *msglen, + /* + * These statistics are included no matter which URL we use. + */ +- obj = json_object_new_string("1.2"); ++ obj = json_object_new_string("1.2.1"); + CHECKMEM(obj); + json_object_object_add(bindstats, "json-stats-version", obj); + +diff --git a/bin/named/update.c b/bin/named/update.c +index 6ad7d27..dccc543 100644 +--- a/bin/named/update.c ++++ b/bin/named/update.c +@@ -1526,6 +1526,17 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { + isc_task_t *zonetask = NULL; + ns_client_t *evclient; + ++ result = isc_quota_attach(&ns_g_server->updquota, ++ &(isc_quota_t *){ NULL }); ++ if (result != ISC_R_SUCCESS) { ++ update_log(client, zone, LOGLEVEL_PROTOCOL, ++ "update failed: too many DNS UPDATEs queued (%s)", ++ isc_result_totext(result)); ++ isc_stats_increment(ns_g_server->nsstats, ++ dns_nsstatscounter_updatequota); ++ CHECK(DNS_R_DROP); ++ } ++ + event = (update_event_t *) + isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, + update_action, NULL, sizeof(*event)); +@@ -1652,7 +1663,12 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) { + * We are still in the client task context, so we can + * simply give an error response without switching tasks. + */ +- respond(client, result); ++ if (result == DNS_R_DROP) { ++ ns_client_next(client, result); ++ } else { ++ respond(client, result); ++ } ++ + if (zone != NULL) + dns_zone_detach(&zone); + } +@@ -3385,6 +3401,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) { + dns_zone_detach(&uev->zone); + client->nupdates--; + respond(client, uev->result); ++ isc_quota_detach(&(isc_quota_t *){ &ns_g_server->updquota }); + isc_event_free(&event); + ns_client_detach(&client); + } +@@ -3402,6 +3419,8 @@ forward_fail(isc_task_t *task, isc_event_t *event) { + INSIST(client->nupdates > 0); + client->nupdates--; + respond(client, DNS_R_SERVFAIL); ++ ++ isc_quota_detach(&(isc_quota_t *){ &ns_g_server->updquota }); + isc_event_free(&event); + ns_client_detach(&client); + } +@@ -3439,6 +3458,8 @@ forward_done(isc_task_t *task, isc_event_t *event) { + client->nupdates--; + ns_client_sendraw(client, uev->answer); + dns_message_detach(&uev->answer); ++ ++ isc_quota_detach(&(isc_quota_t *){ &ns_g_server->updquota }); + isc_event_free(&event); + ns_client_detach(&client); + } +@@ -3472,6 +3493,17 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { + isc_task_t *zonetask = NULL; + ns_client_t *evclient; + ++ result = isc_quota_attach(&ns_g_server->updquota, ++ &(isc_quota_t *){ NULL }); ++ if (result != ISC_R_SUCCESS) { ++ update_log(client, zone, LOGLEVEL_PROTOCOL, ++ "update failed: too many DNS UPDATEs queued (%s)", ++ isc_result_totext(result)); ++ isc_stats_increment(ns_g_server->nsstats, ++ dns_nsstatscounter_updatequota); ++ return (DNS_R_DROP); ++ } ++ + /* + * This may take some time so replace this client. + */ +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index c17f168..9aca6d7 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -15105,6 +15105,21 @@ HOST-127.EXAMPLE. MX 0 . + + + ++ ++ ++ UpdateQuota ++ ++ ++ ++ ++ ++ ++ This indicates the number of times a dynamic update or update ++ forwarding request was rejected because the number of pending ++ requests exceeded the update quota. ++ ++ ++ + + + RateDropped +-- +2.39.2 + diff --git a/SOURCES/bind-9.16-CVE-2022-3094-2.patch b/SOURCES/bind-9.16-CVE-2022-3094-2.patch new file mode 100644 index 0000000..f4ec472 --- /dev/null +++ b/SOURCES/bind-9.16-CVE-2022-3094-2.patch @@ -0,0 +1,136 @@ +From d9a03233c6ea11f20c2fbeca87b763673859f8b2 Mon Sep 17 00:00:00 2001 +From: Evan Hunt +Date: Thu, 1 Sep 2022 16:22:46 -0700 +Subject: [PATCH] add a configuration option for the update quota + +add an "update-quota" option to configure the update quota. + +(cherry picked from commit f57758a7303ad0034ff2ff08eaaf2ef899630f19) +--- + bin/named/config.c | 1 + + bin/named/named.conf.docbook | 2 ++ + bin/named/server.c | 1 + + bin/tests/system/checkconf/good.conf | 1 + + doc/arm/Bv9ARM-book.xml | 11 +++++++++++ + doc/arm/options.grammar.xml | 1 + + doc/misc/options | 1 + + lib/isccfg/namedconf.c | 1 + + 8 files changed, 19 insertions(+) + +diff --git a/bin/named/config.c b/bin/named/config.c +index 62d1e88..e3731cf 100644 +--- a/bin/named/config.c ++++ b/bin/named/config.c +@@ -134,6 +134,7 @@ options {\n\ + transfers-per-ns 2;\n\ + # treat-cr-as-space ;\n\ + trust-anchor-telemetry yes;\n\ ++ update-quota 100;\n\ + # use-id-pool ;\n\ + # use-ixfr ;\n\ + \n\ +diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook +index 6565fce..5842cb5 100644 +--- a/bin/named/named.conf.docbook ++++ b/bin/named/named.conf.docbook +@@ -455,6 +455,7 @@ options { + trust-anchor-telemetry boolean; // experimental + try-tcp-refresh boolean; + update-check-ksk boolean; ++ update-quota integer; + use-alt-transfer-source boolean; + use-v4-udp-ports { portrange; ... }; + use-v6-udp-ports { portrange; ... }; +@@ -864,6 +865,7 @@ view string [ class ] { + type ( delegation-only | forward | hint | master | redirect + | slave | static-stub | stub ); + update-check-ksk boolean; ++ update-quota integer; + update-policy ( local | { ( deny | grant ) string ( + 6to4-self | external | krb5-self | krb5-selfsub | + krb5-subdomain | ms-self | ms-selfsub | ms-subdomain | +diff --git a/bin/named/server.c b/bin/named/server.c +index f09b895..7af90d0 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -7792,6 +7792,7 @@ load_configuration(const char *filename, ns_server_t *server, + configure_server_quota(maps, "tcp-clients", &server->tcpquota); + configure_server_quota(maps, "recursive-clients", + &server->recursionquota); ++ configure_server_quota(maps, "update-quota", &server->updquota); + + if (server->recursionquota.max > 1000) { + int margin = ISC_MAX(100, ns_g_cpus + 1); +diff --git a/bin/tests/system/checkconf/good.conf b/bin/tests/system/checkconf/good.conf +index 1359cf3..5d9b292 100644 +--- a/bin/tests/system/checkconf/good.conf ++++ b/bin/tests/system/checkconf/good.conf +@@ -63,6 +63,7 @@ options { + serial-queries 10; + serial-query-rate 100; + server-id none; ++ update-quota 200; + max-cache-size 20000000000000; + nta-lifetime 604800; + nta-recheck 604800; +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index 9aca6d7..acf772b 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -8599,6 +8599,17 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; + + + ++ ++ update-quota ++ ++ ++ This is the maximum number of simultaneous DNS UPDATE messages that ++ the server will accept for updating local authoritiative zones or ++ forwarding to a primary server. The default is 100. ++ ++ ++ ++ + + + +diff --git a/doc/arm/options.grammar.xml b/doc/arm/options.grammar.xml +index 793ac0b..1d17ea8 100644 +--- a/doc/arm/options.grammar.xml ++++ b/doc/arm/options.grammar.xml +@@ -277,6 +277,7 @@ + trust-anchor-telemetry boolean; // experimental + try-tcp-refresh boolean; + update-check-ksk boolean; ++ update-quota integer; + use-alt-transfer-source boolean; + use-v4-udp-ports { portrange; ... }; + use-v6-udp-ports { portrange; ... }; +diff --git a/doc/misc/options b/doc/misc/options +index fde93c7..e6d6ba6 100644 +--- a/doc/misc/options ++++ b/doc/misc/options +@@ -357,6 +357,7 @@ options { + trust-anchor-telemetry ; // experimental + try-tcp-refresh ; + update-check-ksk ; ++ update-quota ; + use-alt-transfer-source ; + use-id-pool ; // obsolete + use-ixfr ; // obsolete +diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c +index b562f95..667111c 100644 +--- a/lib/isccfg/namedconf.c ++++ b/lib/isccfg/namedconf.c +@@ -1136,6 +1136,7 @@ options_clauses[] = { + { "transfers-out", &cfg_type_uint32, 0 }, + { "transfers-per-ns", &cfg_type_uint32, 0 }, + { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, ++ { "update-quota", &cfg_type_uint32, 0 }, + { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, + { "use-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, + { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, +-- +2.39.2 + diff --git a/SOURCES/bind-9.16-CVE-2022-3094-3.patch b/SOURCES/bind-9.16-CVE-2022-3094-3.patch new file mode 100644 index 0000000..1d39423 --- /dev/null +++ b/SOURCES/bind-9.16-CVE-2022-3094-3.patch @@ -0,0 +1,553 @@ +From cba333b262b7ee0034a66cc93cf27f6c4918eea2 Mon Sep 17 00:00:00 2001 +From: Evan Hunt +Date: Tue, 8 Nov 2022 17:32:41 -0800 +Subject: [PATCH] move update ACL and update-policy checks before quota + +check allow-update, update-policy, and allow-update-forwarding before +consuming quota slots, so that unauthorized clients can't fill the +quota. + +(this moves the access check before the prerequisite check, which +violates the precise wording of RFC 2136. however, RFC co-author Paul +Vixie has stated that the RFC is mistaken on this point; it should have +said that access checking must happen *no later than* the completion of +prerequisite checks, not that it must happen exactly then.) + +(cherry picked from commit 964f559edb5036880b8e463b8f190b9007ee055d) +--- + bin/named/update.c | 440 ++++++++++++++++++++++++++++++--------------- + 1 file changed, 298 insertions(+), 142 deletions(-) + +diff --git a/bin/named/update.c b/bin/named/update.c +index 8853ee7..4d1fe78 100644 +--- a/bin/named/update.c ++++ b/bin/named/update.c +@@ -251,6 +251,9 @@ static void updatedone_action(isc_task_t *task, isc_event_t *event); + static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); + static void forward_done(isc_task_t *task, isc_event_t *event); + static isc_result_t add_rr_prepare_action(void *data, rr_t *rr); ++static isc_result_t ++rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, ++ const dns_rdata_t *rdata, bool *flag); + + /**************************************************************************/ + +@@ -328,23 +331,24 @@ checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename, + { + char namebuf[DNS_NAME_FORMATSIZE]; + char classbuf[DNS_RDATACLASS_FORMATSIZE]; +- int level; + isc_result_t result; ++ bool update_possible = ++ ((updateacl != NULL && !dns_acl_isnone(updateacl)) || ++ ssutable != NULL); + + result = ns_client_checkaclsilent(client, NULL, queryacl, true); + if (result != ISC_R_SUCCESS) { ++ int level = update_possible ? ISC_LOG_ERROR : ISC_LOG_INFO; ++ + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(client->view->rdclass, classbuf, + sizeof(classbuf)); + +- level = (updateacl == NULL && ssutable == NULL) ? +- ISC_LOG_INFO : ISC_LOG_ERROR; +- + ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, + NS_LOGMODULE_UPDATE, level, + "update '%s/%s' denied due to allow-query", + namebuf, classbuf); +- } else if (updateacl == NULL && ssutable == NULL) { ++ } else if (!update_possible) { + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(client->view->rdclass, classbuf, + sizeof(classbuf)); +@@ -1525,6 +1529,277 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { + update_event_t *event = NULL; + isc_task_t *zonetask = NULL; + ns_client_t *evclient; ++#if 1 ++ dns_ssutable_t *ssutable = NULL; ++ dns_message_t *request = client->message; ++ dns_rdataclass_t zoneclass; ++ dns_rdatatype_t covers; ++ dns_name_t *zonename = NULL; ++ dns_db_t *db = NULL; ++ dns_dbversion_t *ver = NULL; ++ ++ CHECK(dns_zone_getdb(zone, &db)); ++ zonename = dns_db_origin(db); ++ zoneclass = dns_db_class(db); ++ dns_zone_getssutable(zone, &ssutable); ++ dns_db_currentversion(db, &ver); ++ ++ /* ++ * Update message processing can leak record existence information ++ * so check that we are allowed to query this zone. Additionally, ++ * if we would refuse all updates for this zone, we bail out here. ++ */ ++ CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), ++ dns_zone_getorigin(zone), ++ dns_zone_getupdateacl(zone), ssutable)); ++ ++ /* ++ * Check requestor's permissions. ++ */ ++ if (ssutable == NULL) ++ CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), ++ "update", zonename, false, false)); ++ else if (client->signer == NULL && !TCPCLIENT(client)) ++ CHECK(checkupdateacl(client, NULL, "update", zonename, ++ false, true)); ++ ++ if (dns_zone_getupdatedisabled(zone)) ++ FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled " ++ "because the zone is frozen. Use " ++ "'rndc thaw' to re-enable updates."); ++ ++ /* ++ * Perform the Update Section Prescan. ++ */ ++ ++ for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); ++ result == ISC_R_SUCCESS; ++ result = dns_message_nextname(request, DNS_SECTION_UPDATE)) ++ { ++ dns_name_t *name = NULL; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ dns_ttl_t ttl; ++ dns_rdataclass_t update_class; ++ get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, ++ &name, &rdata, &covers, &ttl, &update_class); ++ ++ if (! dns_name_issubdomain(name, zonename)) ++ FAILC(DNS_R_NOTZONE, ++ "update RR is outside zone"); ++ if (update_class == zoneclass) { ++ /* ++ * Check for meta-RRs. The RFC2136 pseudocode says ++ * check for ANY|AXFR|MAILA|MAILB, but the text adds ++ * "or any other QUERY metatype" ++ */ ++ if (dns_rdatatype_ismeta(rdata.type)) { ++ FAILC(DNS_R_FORMERR, ++ "meta-RR in update"); ++ } ++ result = dns_zone_checknames(zone, name, &rdata); ++ if (result != ISC_R_SUCCESS) ++ FAIL(DNS_R_REFUSED); ++ } else if (update_class == dns_rdataclass_any) { ++ if (ttl != 0 || rdata.length != 0 || ++ (dns_rdatatype_ismeta(rdata.type) && ++ rdata.type != dns_rdatatype_any)) ++ FAILC(DNS_R_FORMERR, ++ "meta-RR in update"); ++ } else if (update_class == dns_rdataclass_none) { ++ if (ttl != 0 || ++ dns_rdatatype_ismeta(rdata.type)) ++ FAILC(DNS_R_FORMERR, ++ "meta-RR in update"); ++ } else { ++ update_log(client, zone, ISC_LOG_WARNING, ++ "update RR has incorrect class %d", ++ update_class); ++ FAIL(DNS_R_FORMERR); ++ } ++ ++ /* ++ * draft-ietf-dnsind-simple-secure-update-01 says ++ * "Unlike traditional dynamic update, the client ++ * is forbidden from updating NSEC records." ++ */ ++ if (rdata.type == dns_rdatatype_nsec3) { ++ FAILC(DNS_R_REFUSED, ++ "explicit NSEC3 updates are not allowed " ++ "in secure zones"); ++ } else if (rdata.type == dns_rdatatype_nsec) { ++ FAILC(DNS_R_REFUSED, ++ "explicit NSEC updates are not allowed " ++ "in secure zones"); ++ } else if (rdata.type == dns_rdatatype_rrsig && ++ !dns_name_equal(name, zonename)) { ++ FAILC(DNS_R_REFUSED, ++ "explicit RRSIG updates are currently " ++ "not supported in secure zones except " ++ "at the apex"); ++ } ++ ++ if (ssutable != NULL) { ++ isc_netaddr_t netaddr; ++ dst_key_t *tsigkey = NULL; ++ isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); ++ ++ if (client->message->tsigkey != NULL) ++ tsigkey = client->message->tsigkey->key; ++ ++ if (rdata.type != dns_rdatatype_any) { ++ if (!dns_ssutable_checkrules2 ++ (ssutable, client->signer, name, &netaddr, ++ TCPCLIENT(client), ++ &ns_g_server->aclenv, ++ rdata.type, tsigkey)) ++ { ++ FAILC(DNS_R_REFUSED, ++ "rejected by secure update"); ++ } ++ } else { ++ if (!ssu_checkall(db, ver, name, ssutable, ++ client->signer, ++ &netaddr, ++ TCPCLIENT(client), ++ tsigkey)) ++ { ++ FAILC(DNS_R_REFUSED, ++ "rejected by secure update"); ++ } ++ } ++ } ++ } ++ if (result != ISC_R_NOMORE) ++ FAIL(result); ++ ++ update_log(client, zone, LOGLEVEL_DEBUG, ++ "update section prescan OK"); ++#if 0 ++ if (ssutable == NULL) { ++ CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), ++ // zonename ++ "update", dns_zone_getorigin(zone), false, ++ false)); ++ } else if (client->signer == NULL && !TCPCLIENT(client)) { ++ CHECK(checkupdateacl(client, NULL, "update", ++ dns_zone_getorigin(zone), false, true)); ++ } ++ ++ if (dns_zone_getupdatedisabled(zone)) { ++ FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled " ++ "because the zone is frozen. Use " ++ "'rndc thaw' to re-enable updates."); ++ } ++ ++ /* ++ * Prescan the update section, checking for updates that ++ * are illegal or violate policy. ++ */ ++ for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); ++ result == ISC_R_SUCCESS; ++ result = dns_message_nextname(request, DNS_SECTION_UPDATE)) ++ { ++ dns_name_t *name = NULL; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ dns_ttl_t ttl; ++ dns_rdataclass_t update_class; ++ ++ get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name, ++ &rdata, &covers, &ttl, &update_class); ++ ++ if (!dns_name_issubdomain(name, zonename)) { ++ FAILC(DNS_R_NOTZONE, "update RR is outside zone"); ++ } ++ if (update_class == zoneclass) { ++ /* ++ * Check for meta-RRs. The RFC2136 pseudocode says ++ * check for ANY|AXFR|MAILA|MAILB, but the text adds ++ * "or any other QUERY metatype" ++ */ ++ if (dns_rdatatype_ismeta(rdata.type)) { ++ FAILC(DNS_R_FORMERR, "meta-RR in update"); ++ } ++ result = dns_zone_checknames(zone, name, &rdata); ++ if (result != ISC_R_SUCCESS) { ++ FAIL(DNS_R_REFUSED); ++ } ++ } else if (update_class == dns_rdataclass_any) { ++ if (ttl != 0 || rdata.length != 0 || ++ (dns_rdatatype_ismeta(rdata.type) && ++ rdata.type != dns_rdatatype_any)) ++ { ++ FAILC(DNS_R_FORMERR, "meta-RR in update"); ++ } ++ } else if (update_class == dns_rdataclass_none) { ++ if (ttl != 0 || dns_rdatatype_ismeta(rdata.type)) { ++ FAILC(DNS_R_FORMERR, "meta-RR in update"); ++ } ++ } else { ++ update_log(client, zone, ISC_LOG_WARNING, ++ "update RR has incorrect class %d", ++ update_class); ++ FAIL(DNS_R_FORMERR); ++ } ++ ++ /* ++ * draft-ietf-dnsind-simple-secure-update-01 says ++ * "Unlike traditional dynamic update, the client ++ * is forbidden from updating NSEC records." ++ */ ++ if (rdata.type == dns_rdatatype_nsec3) { ++ FAILC(DNS_R_REFUSED, "explicit NSEC3 updates are not " ++ "allowed " ++ "in secure zones"); ++ } else if (rdata.type == dns_rdatatype_nsec) { ++ FAILC(DNS_R_REFUSED, "explicit NSEC updates are not " ++ "allowed " ++ "in secure zones"); ++ } else if (rdata.type == dns_rdatatype_rrsig && ++ !dns_name_equal(name, zonename)) ++ { ++ FAILC(DNS_R_REFUSED, "explicit RRSIG updates are " ++ "currently " ++ "not supported in secure zones " ++ "except " ++ "at the apex"); ++ } ++ ++ if (ssutable != NULL) { ++ isc_netaddr_t netaddr; ++ dst_key_t *tsigkey = NULL; ++ isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); ++ ++ if (client->message->tsigkey != NULL) { ++ tsigkey = client->message->tsigkey->key; ++ } ++ ++ if (rdata.type != dns_rdatatype_any) { ++ if (!dns_ssutable_checkrules( ++ ssutable, client->signer, name, ++ &netaddr, TCPCLIENT(client), env, ++ rdata.type, tsigkey)) ++ { ++ FAILC(DNS_R_REFUSED, "rejected by " ++ "secure update"); ++ } ++ } else { ++ if (!ssu_checkall(db, ver, name, ssutable, ++ client->signer, &netaddr, env, ++ TCPCLIENT(client), tsigkey)) ++ { ++ FAILC(DNS_R_REFUSED, "rejected by " ++ "secure update"); ++ } ++ } ++ } ++ } ++ if (result != ISC_R_NOMORE) { ++ FAIL(result); ++ } ++ ++ update_log(client, zone, LOGLEVEL_DEBUG, "update section prescan OK"); ++#endif ++#endif + + result = isc_quota_attach(&ns_g_server->updquota, + &(isc_quota_t *){ NULL }); +@@ -1558,6 +1833,15 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { + failure: + if (event != NULL) + isc_event_free(ISC_EVENT_PTR(&event)); ++ if (db != NULL) { ++ dns_db_closeversion(db, &ver, false); ++ dns_db_detach(&db); ++ } ++ ++ if (ssutable != NULL) { ++ dns_ssutable_detach(&ssutable); ++ } ++ + return (result); + } + +@@ -1644,9 +1928,6 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) { + CHECK(send_update_event(client, zone)); + break; + case dns_zone_slave: +- CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), +- "update forwarding", zonename, true, +- false)); + CHECK(send_forward_event(client, zone)); + break; + default: +@@ -1656,7 +1937,6 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) { + + failure: + if (result == DNS_R_REFUSED) { +- INSIST(dns_zone_gettype(zone) == dns_zone_slave); + inc_stats(zone, dns_nsstatscounter_updaterej); + } + /* +@@ -2520,7 +2800,7 @@ update_action(isc_task_t *task, isc_event_t *event) { + dns_rdatatype_t covers; + dns_message_t *request = client->message; + dns_rdataclass_t zoneclass; +- dns_name_t *zonename; ++ dns_name_t *zonename = NULL; + dns_ssutable_t *ssutable = NULL; + dns_fixedname_t tmpnamefixed; + dns_name_t *tmpname = NULL; +@@ -2542,14 +2822,7 @@ update_action(isc_task_t *task, isc_event_t *event) { + zonename = dns_db_origin(db); + zoneclass = dns_db_class(db); + dns_zone_getssutable(zone, &ssutable); +- +- /* +- * Update message processing can leak record existence information +- * so check that we are allowed to query this zone. Additionally +- * if we would refuse all updates for this zone we bail out here. +- */ +- CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename, +- dns_zone_getupdateacl(zone), ssutable)); ++ options = dns_zone_getoptions(zone); + + /* + * Get old and new versions now that queryacl has been checked. +@@ -2673,134 +2946,10 @@ update_action(isc_task_t *task, isc_event_t *event) { + update_log(client, zone, LOGLEVEL_DEBUG, + "prerequisites are OK"); + +- /* +- * Check Requestor's Permissions. It seems a bit silly to do this +- * only after prerequisite testing, but that is what RFC2136 says. +- */ +- if (ssutable == NULL) +- CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), +- "update", zonename, false, false)); +- else if (client->signer == NULL && !TCPCLIENT(client)) +- CHECK(checkupdateacl(client, NULL, "update", zonename, +- false, true)); +- +- if (dns_zone_getupdatedisabled(zone)) +- FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled " +- "because the zone is frozen. Use " +- "'rndc thaw' to re-enable updates."); +- +- /* +- * Perform the Update Section Prescan. +- */ +- +- for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); +- result == ISC_R_SUCCESS; +- result = dns_message_nextname(request, DNS_SECTION_UPDATE)) +- { +- dns_name_t *name = NULL; +- dns_rdata_t rdata = DNS_RDATA_INIT; +- dns_ttl_t ttl; +- dns_rdataclass_t update_class; +- get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, +- &name, &rdata, &covers, &ttl, &update_class); +- +- if (! dns_name_issubdomain(name, zonename)) +- FAILC(DNS_R_NOTZONE, +- "update RR is outside zone"); +- if (update_class == zoneclass) { +- /* +- * Check for meta-RRs. The RFC2136 pseudocode says +- * check for ANY|AXFR|MAILA|MAILB, but the text adds +- * "or any other QUERY metatype" +- */ +- if (dns_rdatatype_ismeta(rdata.type)) { +- FAILC(DNS_R_FORMERR, +- "meta-RR in update"); +- } +- result = dns_zone_checknames(zone, name, &rdata); +- if (result != ISC_R_SUCCESS) +- FAIL(DNS_R_REFUSED); +- } else if (update_class == dns_rdataclass_any) { +- if (ttl != 0 || rdata.length != 0 || +- (dns_rdatatype_ismeta(rdata.type) && +- rdata.type != dns_rdatatype_any)) +- FAILC(DNS_R_FORMERR, +- "meta-RR in update"); +- } else if (update_class == dns_rdataclass_none) { +- if (ttl != 0 || +- dns_rdatatype_ismeta(rdata.type)) +- FAILC(DNS_R_FORMERR, +- "meta-RR in update"); +- } else { +- update_log(client, zone, ISC_LOG_WARNING, +- "update RR has incorrect class %d", +- update_class); +- FAIL(DNS_R_FORMERR); +- } +- +- /* +- * draft-ietf-dnsind-simple-secure-update-01 says +- * "Unlike traditional dynamic update, the client +- * is forbidden from updating NSEC records." +- */ +- if (rdata.type == dns_rdatatype_nsec3) { +- FAILC(DNS_R_REFUSED, +- "explicit NSEC3 updates are not allowed " +- "in secure zones"); +- } else if (rdata.type == dns_rdatatype_nsec) { +- FAILC(DNS_R_REFUSED, +- "explicit NSEC updates are not allowed " +- "in secure zones"); +- } else if (rdata.type == dns_rdatatype_rrsig && +- !dns_name_equal(name, zonename)) { +- FAILC(DNS_R_REFUSED, +- "explicit RRSIG updates are currently " +- "not supported in secure zones except " +- "at the apex"); +- } +- +- if (ssutable != NULL) { +- isc_netaddr_t netaddr; +- dst_key_t *tsigkey = NULL; +- isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); +- +- if (client->message->tsigkey != NULL) +- tsigkey = client->message->tsigkey->key; +- +- if (rdata.type != dns_rdatatype_any) { +- if (!dns_ssutable_checkrules2 +- (ssutable, client->signer, name, &netaddr, +- TCPCLIENT(client), +- &ns_g_server->aclenv, +- rdata.type, tsigkey)) +- { +- FAILC(DNS_R_REFUSED, +- "rejected by secure update"); +- } +- } else { +- if (!ssu_checkall(db, ver, name, ssutable, +- client->signer, +- &netaddr, +- TCPCLIENT(client), +- tsigkey)) +- { +- FAILC(DNS_R_REFUSED, +- "rejected by secure update"); +- } +- } +- } +- } +- if (result != ISC_R_NOMORE) +- FAIL(result); +- +- update_log(client, zone, LOGLEVEL_DEBUG, +- "update section prescan OK"); +- + /* + * Process the Update Section. + */ + +- options = dns_zone_getoptions(zone); + options2 = dns_zone_getoptions2(zone); + for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); + result == ISC_R_SUCCESS; +@@ -3494,6 +3643,13 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { + isc_task_t *zonetask = NULL; + ns_client_t *evclient; + ++ result = checkupdateacl(client, dns_zone_getforwardacl(zone), ++ "update forwarding", dns_zone_getorigin(zone), ++ true, false); ++ if (result != ISC_R_SUCCESS) { ++ return (result); ++ } ++ + result = isc_quota_attach(&ns_g_server->updquota, + &(isc_quota_t *){ NULL }); + if (result != ISC_R_SUCCESS) { +-- +2.39.2 + diff --git a/SOURCES/bind-9.16-CVE-2022-3094-test.patch b/SOURCES/bind-9.16-CVE-2022-3094-test.patch new file mode 100644 index 0000000..fe93e26 --- /dev/null +++ b/SOURCES/bind-9.16-CVE-2022-3094-test.patch @@ -0,0 +1,266 @@ +From 3d84c651f823cb90b73fd736d32ad6de57b11610 Mon Sep 17 00:00:00 2001 +From: Evan Hunt +Date: Wed, 9 Nov 2022 21:56:16 -0800 +Subject: [PATCH] test failure conditions + +verify that updates are refused when the client is disallowed by +allow-query, and update forwarding is refused when the client is +is disallowed by update-forwarding. + +verify that "too many DNS UPDATEs" appears in the log file when too +many simultaneous updates are processing. + +(cherry picked from commit b91339b80e5b82a56622c93cc1e3cca2d0c11bc0) +--- + bin/tests/system/nsupdate/ns1/named.conf.in | 2 + + bin/tests/system/nsupdate/tests.sh | 28 +++++++++++++ + bin/tests/system/upforwd/clean.sh | 2 + + .../ns3/{named.conf.in => named1.conf.in} | 7 +++- + bin/tests/system/upforwd/ns3/named2.conf.in | 41 +++++++++++++++++++ + bin/tests/system/upforwd/setup.sh | 2 +- + bin/tests/system/upforwd/tests.sh | 40 ++++++++++++++++++ + 7 files changed, 120 insertions(+), 2 deletions(-) + rename bin/tests/system/upforwd/ns3/{named.conf.in => named1.conf.in} (85%) + create mode 100644 bin/tests/system/upforwd/ns3/named2.conf.in + +diff --git a/bin/tests/system/nsupdate/ns1/named.conf.in b/bin/tests/system/nsupdate/ns1/named.conf.in +index cb80269..228ad6a 100644 +--- a/bin/tests/system/nsupdate/ns1/named.conf.in ++++ b/bin/tests/system/nsupdate/ns1/named.conf.in +@@ -20,6 +20,7 @@ options { + listen-on-v6 { none; }; + recursion no; + notify yes; ++ update-quota 1; + }; + + key rndc_key { +@@ -76,6 +77,7 @@ zone "other.nil" { + check-integrity no; + check-mx warn; + update-policy local; ++ allow-query { !10.53.0.2; any; }; + allow-query-on { 10.53.0.1; 127.0.0.1; }; + allow-transfer { any; }; + }; +diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh +index f8994ff..4cabf8d 100755 +--- a/bin/tests/system/nsupdate/tests.sh ++++ b/bin/tests/system/nsupdate/tests.sh +@@ -1069,6 +1069,34 @@ END + grep "NSEC3PARAM has excessive iterations (> 150)" nsupdate.out-$n >/dev/null || ret=1 + [ $ret = 0 ] || { echo_i "failed"; status=1; } + ++n=$((n + 1)) ++ret=0 ++echo_i "check that update is rejected if query is not allowed ($n)" ++{ ++ $NSUPDATE -d < nsupdate.out.test$n 2>&1 ++grep 'status: REFUSED' nsupdate.out.test$n > /dev/null || ret=1 ++[ $ret = 0 ] || { echo_i "failed"; status=1; } ++ ++n=$((n + 1)) ++ret=0 ++echo_i "check that update is rejected if quota is exceeded ($n)" ++for loop in 1 2 3 4 5 6 7 8 9 10; do ++{ ++ $NSUPDATE -l -p ${PORT} -k ns1/session.key > nsupdate.out.test$n-${loop} 2>&1 < nsupdate.out.$n 2>&1 ++grep REFUSED nsupdate.out.$n > /dev/null || ret=1 ++if [ $ret != 0 ] ; then echo_i "failed"; status=`expr $status + $ret`; fi ++n=`expr $n + 1` ++ ++n=$((n + 1)) ++ret=0 ++echo_i "attempting updates that should exceed quota ($n)" ++# lower the update quota to 1. ++copy_setports ns3/named2.conf.in ns3/named.conf ++$RNDCCMD 10.53.0.3 reconfig ++nextpart ns3/named.run > /dev/null ++for loop in 1 2 3 4 5 6 7 8 9 10; do ++{ ++ $NSUPDATE -- - > /dev/null 2>&1 < - 32:9.11.36-8.2 +* Tue Sep 19 2023 Petr Menšík - 32:9.11.36-11 - Prevent exahustion of memory from control channel (CVE-2023-3341) -* Thu Jun 22 2023 Petr Menšík - 32:9.11.36-8.1 +* Thu Jun 22 2023 Petr Menšík - 32:9.11.36-10 - Prevent the cache going over the configured limit (CVE-2023-2828) +* Wed Feb 08 2023 Petr Menšík - 32:9.11.36-9 +- Prevent flooding with UPDATE requests (CVE-2022-3094) +- include upstream test for that change + * Thu Oct 13 2022 Petr Menšík - 32:9.11.36-8 - Correct regression preventing bind-dyndb-ldap build (#2133889)