From 681ac40e931f3c8c887f16f3871996cb24fcaebc Mon Sep 17 00:00:00 2001 From: chengyechun Date: Mon, 18 Mar 2024 10:40:52 +0800 Subject: [PATCH] fix CVE and sync some patches from upstream --- ...rt-CVE-2022-3094-add-an-update-quota.patch | 17 +- backport-CVE-2023-4408.patch | 1645 +++++++++++++++++ backport-CVE-2023-50387-CVE-2023-50868.patch | 498 +++++ backport-CVE-2023-5517.patch | 117 ++ backport-CVE-2023-5679.patch | 38 + backport-CVE-2023-6516.patch | 294 +++ ...internal-memory-allocator-by-default.patch | 14 +- ...t-and-isc_ht_iter_create-return-void.patch | 408 ++++ ...t-lock-free-queue-with-simple-locked.patch | 1353 ++++++++++++++ ...cy-max-zone-ttl-rejects-zone-with-to.patch | 107 ++ ...ncorrect-detach-in-update-processing.patch | 19 +- ...-with-both-dnssec-policy-and-max-zon.patch | 102 + bind.spec | 140 +- 13 files changed, 4666 insertions(+), 86 deletions(-) create mode 100644 backport-CVE-2023-4408.patch create mode 100644 backport-CVE-2023-50387-CVE-2023-50868.patch create mode 100644 backport-CVE-2023-5517.patch create mode 100644 backport-CVE-2023-5679.patch create mode 100644 backport-CVE-2023-6516.patch rename backport-Disable-the-internale-memory-allocator-by-default.patch => backport-Disable-the-internal-memory-allocator-by-default.patch (77%) create mode 100644 backport-Make-isc_ht_init-and-isc_ht_iter_create-return-void.patch create mode 100644 backport-Replace-netievent-lock-free-queue-with-simple-locked.patch create mode 100644 backport-Test-dnssec-policy-max-zone-ttl-rejects-zone-with-to.patch create mode 100644 backport-warn-about-zones-with-both-dnssec-policy-and-max-zon.patch diff --git a/backport-CVE-2022-3094-add-an-update-quota.patch b/backport-CVE-2022-3094-add-an-update-quota.patch index 3d3e678..f004366 100644 --- a/backport-CVE-2022-3094-add-an-update-quota.patch +++ b/backport-CVE-2022-3094-add-an-update-quota.patch @@ -150,7 +150,7 @@ index a970a28..540bc2e 100644 isc_quota_destroy(&sctx->tcpquota); isc_quota_destroy(&sctx->xfroutquota); diff --git a/lib/ns/update.c b/lib/ns/update.c -index 582d4ff..a1650de 100644 +index ddda25a..a69b6e5 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -1544,6 +1544,19 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { @@ -173,7 +173,7 @@ index 582d4ff..a1650de 100644 event = (update_event_t *)isc_event_allocate( client->mctx, client, DNS_EVENT_UPDATE, update_action, NULL, sizeof(*event)); -@@ -1685,12 +1698,19 @@ failure: +@@ -1682,12 +1695,19 @@ failure: dns_zone_gettype(zone) == dns_zone_mirror); inc_stats(client, zone, ns_statscounter_updaterej); } @@ -194,7 +194,7 @@ index 582d4ff..a1650de 100644 if (zone != NULL) { dns_zone_detach(&zone); } -@@ -3498,6 +3518,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) { +@@ -3494,6 +3514,7 @@ updatedone_action(isc_task_t *task, isc_event_t *event) { respond(client, uev->result); @@ -202,7 +202,7 @@ index 582d4ff..a1650de 100644 isc_event_free(&event); isc_nmhandle_detach(&client->updatehandle); } -@@ -3514,6 +3535,8 @@ forward_fail(isc_task_t *task, isc_event_t *event) { +@@ -3510,6 +3531,8 @@ forward_fail(isc_task_t *task, isc_event_t *event) { INSIST(client->nupdates > 0); client->nupdates--; respond(client, DNS_R_SERVFAIL); @@ -211,16 +211,16 @@ index 582d4ff..a1650de 100644 isc_event_free(&event); isc_nmhandle_detach(&client->updatehandle); } -@@ -3551,6 +3574,8 @@ forward_done(isc_task_t *task, isc_event_t *event) { +@@ -3547,6 +3570,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 *){ &client->manager->sctx->updquota }); isc_event_free(&event); + isc_nmhandle_detach(&client->reqhandle); isc_nmhandle_detach(&client->updatehandle); - } -@@ -3585,6 +3610,17 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { +@@ -3582,6 +3607,17 @@ send_forward_event(ns_client_t *client, dns_zone_t *zone) { update_event_t *event = NULL; isc_task_t *zonetask = NULL; @@ -239,4 +239,5 @@ index 582d4ff..a1650de 100644 client->mctx, client, DNS_EVENT_UPDATE, forward_action, NULL, sizeof(*event)); -- -GitLab +2.33.0 + diff --git a/backport-CVE-2023-4408.patch b/backport-CVE-2023-4408.patch new file mode 100644 index 0000000..5cd03d4 --- /dev/null +++ b/backport-CVE-2023-4408.patch @@ -0,0 +1,1645 @@ +From 608707b4f5b473e416563bfe0d43e26d6dc4a5c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= +Date: Mon, 11 Sep 2023 10:35:28 +0200 +Subject: [PATCH] Use hashtable when parsing a message + +When parsing messages use a hashtable instead of a linear search to +reduce the amount of work done in findname when there's more than one +name in the section. + +There are two hashtables: + +1) hashtable for owner names - that's constructed for each section when +we hit the second name in the section and destroyed right after parsing +that section; + +2) per-name hashtable - for each name in the section, we construct a new +hashtable for that name if there are more than one rdataset for that +particular name. + +Conflict:Due to the optimization patch 75f9dd8e82 not being merged, the optimization patch uses unreachable to encapsulate INSIST(0);ISC_UNREACHABLE(); In addition, the dns_message_find and dns_message_movename functions are not deleted. +Reference:https://downloads.isc.org/isc/bind/9.16.48/patches/0001-CVE-2023-4408.patch + +(cherry picked from commit b8a96317544c7b310b4f74360825a87b6402ddc2) +--- + bin/plugins/filter-aaaa.c | 2 +- + lib/dns/catz.c | 8 +- + lib/dns/include/dns/name.h | 37 ++- + lib/dns/message.c | 359 +++++++++++++++++------- + lib/dns/name.c | 1 + + lib/dns/rpz.c | 5 +- + lib/isc/ht.c | 557 ++++++++++++++++++++++++++++--------- + lib/isc/include/isc/ht.h | 28 +- + lib/isc/tests/ht_test.c | 4 +- + 9 files changed, 723 insertions(+), 278 deletions(-) + +diff --git a/bin/plugins/filter-aaaa.c b/bin/plugins/filter-aaaa.c +index c390b45..b51f143 100644 +--- a/bin/plugins/filter-aaaa.c ++++ b/bin/plugins/filter-aaaa.c +@@ -355,7 +355,7 @@ plugin_register(const char *parameters, const void *cfg, const char *cfg_file, + } + + isc_mempool_create(mctx, sizeof(filter_data_t), &inst->datapool); +- isc_ht_init(&inst->ht, mctx, 16); ++ isc_ht_init(&inst->ht, mctx, 16, ISC_HT_CASE_SENSITIVE); + isc_mutex_init(&inst->hlock); + + /* +diff --git a/lib/dns/catz.c b/lib/dns/catz.c +index fbe13f4..e27a6ff 100644 +--- a/lib/dns/catz.c ++++ b/lib/dns/catz.c +@@ -418,9 +418,9 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) { + + dns_name_format(&target->name, czname, DNS_NAME_FORMATSIZE); + +- isc_ht_init(&toadd, target->catzs->mctx, 16); ++ isc_ht_init(&toadd, target->catzs->mctx, 16, ISC_HT_CASE_SENSITIVE); + +- isc_ht_init(&tomod, target->catzs->mctx, 16); ++ isc_ht_init(&tomod, target->catzs->mctx, 16, ISC_HT_CASE_SENSITIVE); + + isc_ht_iter_create(newzone->entries, &iter1); + +@@ -605,7 +605,7 @@ dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm, + + isc_refcount_init(&new_zones->refs, 1); + +- isc_ht_init(&new_zones->zones, mctx, 4); ++ isc_ht_init(&new_zones->zones, mctx, 4, ISC_HT_CASE_SENSITIVE); + + isc_mem_attach(mctx, &new_zones->mctx); + new_zones->zmm = zmm; +@@ -657,7 +657,7 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep, + dns_name_init(&new_zone->name, NULL); + dns_name_dup(name, catzs->mctx, &new_zone->name); + +- isc_ht_init(&new_zone->entries, catzs->mctx, 4); ++ isc_ht_init(&new_zone->entries, catzs->mctx, 16, ISC_HT_CASE_SENSITIVE); + + new_zone->updatetimer = NULL; + result = isc_timer_create(catzs->timermgr, isc_timertype_inactive, NULL, +diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h +index 75bc020..4058b56 100644 +--- a/lib/dns/include/dns/name.h ++++ b/lib/dns/include/dns/name.h +@@ -67,6 +67,7 @@ + #include + #include + ++#include + #include + #include + #include /* Required for storage size of dns_label_t. */ +@@ -110,6 +111,7 @@ struct dns_name { + isc_buffer_t *buffer; + ISC_LINK(dns_name_t) link; + ISC_LIST(dns_rdataset_t) list; ++ isc_ht_t *ht; + }; + + #define DNS_NAME_MAGIC ISC_MAGIC('D', 'N', 'S', 'n') +@@ -165,30 +167,24 @@ LIBDNS_EXTERNAL_DATA extern const dns_name_t *dns_wildcardname; + * unsigned char offsets[] = { 0, 6 }; + * dns_name_t value = DNS_NAME_INITABSOLUTE(data, offsets); + */ +-#define DNS_NAME_INITNONABSOLUTE(A, B) \ +- { \ +- DNS_NAME_MAGIC, A, (sizeof(A) - 1), sizeof(B), \ +- DNS_NAMEATTR_READONLY, B, NULL, \ +- { (void *)-1, (void *)-1 }, { \ +- NULL, NULL \ +- } \ ++#define DNS_NAME_INITNONABSOLUTE(A, B) \ ++ { \ ++ DNS_NAME_MAGIC, A, (sizeof(A) - 1), sizeof(B), \ ++ DNS_NAMEATTR_READONLY, B, NULL, \ ++ { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \ + } + +-#define DNS_NAME_INITABSOLUTE(A, B) \ +- { \ +- DNS_NAME_MAGIC, A, sizeof(A), sizeof(B), \ +- DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, B, \ +- NULL, { (void *)-1, (void *)-1 }, { \ +- NULL, NULL \ +- } \ ++#define DNS_NAME_INITABSOLUTE(A, B) \ ++ { \ ++ DNS_NAME_MAGIC, A, sizeof(A), sizeof(B), \ ++ DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, B, \ ++ NULL, { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \ + } + +-#define DNS_NAME_INITEMPTY \ +- { \ +- DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL, \ +- { (void *)-1, (void *)-1 }, { \ +- NULL, NULL \ +- } \ ++#define DNS_NAME_INITEMPTY \ ++ { \ ++ DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL, \ ++ { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \ + } + + /*% +@@ -1355,6 +1351,7 @@ ISC_LANG_ENDDECLS + _n->buffer = NULL; \ + ISC_LINK_INIT(_n, link); \ + ISC_LIST_INIT(_n->list); \ ++ _n->ht = NULL; \ + } while (0) + + #define DNS_NAME_RESET(n) \ +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 5598d32..500705e 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -20,6 +20,8 @@ + #include + + #include ++#include ++#include + #include + #include + #include /* Required for HP/UX (and others?) */ +@@ -503,9 +505,11 @@ msgresetsigs(dns_message_t *msg, bool replying) { + } else { + dns_rdataset_disassociate(msg->tsig); + isc_mempool_put(msg->rdspool, msg->tsig); ++ msg->tsig = NULL; + if (msg->querytsig != NULL) { + dns_rdataset_disassociate(msg->querytsig); + isc_mempool_put(msg->rdspool, msg->querytsig); ++ msg->querytsig = NULL; + } + } + dns_message_puttempname(msg, &msg->tsigname); +@@ -794,6 +798,18 @@ dns_message_detach(dns_message_t **messagep) { + } + } + ++static isc_result_t ++name_hash_add(isc_ht_t *ht, dns_name_t *name, dns_name_t **foundp) { ++ isc_result_t result = isc_ht_find(ht, name->ndata, name->length, ++ (void **)foundp); ++ if (result == ISC_R_SUCCESS) { ++ return (ISC_R_EXISTS); ++ } ++ result = isc_ht_add(ht, name->ndata, name->length, (void *)name); ++ INSIST(result == ISC_R_SUCCESS); ++ return (ISC_R_SUCCESS); ++} ++ + static isc_result_t + findname(dns_name_t **foundname, const dns_name_t *target, + dns_namelist_t *section) { +@@ -837,6 +853,28 @@ dns_message_find(const dns_name_t *name, dns_rdataclass_t rdclass, + return (ISC_R_NOTFOUND); + } + ++typedef struct __attribute__((__packed__)) rds_key { ++ dns_rdataclass_t rdclass; ++ dns_rdatatype_t type; ++ dns_rdatatype_t covers; ++} rds_key_t; ++ ++static isc_result_t ++rds_hash_add(isc_ht_t *ht, dns_rdataset_t *rds, dns_rdataset_t **foundp) { ++ rds_key_t key = { .rdclass = rds->rdclass, ++ .type = rds->type, ++ .covers = rds->covers }; ++ isc_result_t result = isc_ht_find(ht, (const unsigned char *)&key, ++ sizeof(key), (void **)foundp); ++ if (result == ISC_R_SUCCESS) { ++ return (ISC_R_EXISTS); ++ } ++ result = isc_ht_add(ht, (const unsigned char *)&key, sizeof(key), ++ (void *)rds); ++ INSIST(result == ISC_R_SUCCESS); ++ return (ISC_R_SUCCESS); ++} ++ + isc_result_t + dns_message_findtype(const dns_name_t *name, dns_rdatatype_t type, + dns_rdatatype_t covers, dns_rdataset_t **rdataset) { +@@ -962,6 +1000,18 @@ getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + } \ + } while (0) + ++static void ++cleanup_name_hashmaps(dns_namelist_t *section) { ++ dns_name_t *name = NULL; ++ for (name = ISC_LIST_HEAD(*section); name != NULL; ++ name = ISC_LIST_NEXT(name, link)) ++ { ++ if (name->ht != NULL) { ++ isc_ht_destroy(&name->ht); ++ } ++ } ++} ++ + static isc_result_t + getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + unsigned int options) { +@@ -971,13 +1021,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + dns_name_t *name2 = NULL; + dns_rdataset_t *rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; +- isc_result_t result; ++ isc_result_t result = ISC_R_SUCCESS; + dns_rdatatype_t rdtype; + dns_rdataclass_t rdclass; + dns_namelist_t *section = &msg->sections[DNS_SECTION_QUESTION]; + bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0); + bool seen_problem = false; + bool free_name = false; ++ bool free_ht = false; ++ isc_ht_t *name_map = NULL; ++ ++ if (msg->counts[DNS_SECTION_QUESTION] > 1) { ++ isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE); ++ } + + for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) { + name = NULL; +@@ -998,13 +1054,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + goto cleanup; + } + ++ /* If there is only one QNAME, skip the duplicity checks */ ++ if (name_map == NULL) { ++ result = ISC_R_SUCCESS; ++ goto skip_name_check; ++ } ++ + /* + * Run through the section, looking to see if this name + * is already there. If it is found, put back the allocated + * name since we no longer need it, and set our name pointer + * to point to the name we found. + */ +- result = findname(&name2, name, section); ++ result = name_hash_add(name_map, name, &name2); + + /* + * If it is the first name in the section, accept it. +@@ -1016,19 +1078,26 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + * this should be legal or not. In either case we no longer + * need this name pointer. + */ +- if (result != ISC_R_SUCCESS) { ++ skip_name_check: ++ switch (result) { ++ case ISC_R_SUCCESS: + if (!ISC_LIST_EMPTY(*section)) { + DO_ERROR(DNS_R_FORMERR); + } + ISC_LIST_APPEND(*section, name, link); +- free_name = false; +- } else { ++ break; ++ case ISC_R_EXISTS: + dns_message_puttempname(msg, &name); + name = name2; + name2 = NULL; +- free_name = false; ++ break; ++ default: ++ INSIST(0); ++ ISC_UNREACHABLE(); + } + ++ free_name = false; ++ + /* + * Get type and class. + */ +@@ -1058,14 +1127,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + msg->tkey = 1; + } + +- /* +- * Can't ask the same question twice. +- */ +- result = dns_message_find(name, rdclass, rdtype, 0, NULL); +- if (result == ISC_R_SUCCESS) { +- DO_ERROR(DNS_R_FORMERR); +- } +- + /* + * Allocate a new rdatalist. + */ +@@ -1079,6 +1140,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + result = ISC_R_NOMEMORY; + goto cleanup; + } ++ dns_rdataset_init(rdataset); + + /* + * Convert rdatalist to rdataset, and attach the latter to +@@ -1087,32 +1149,71 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + rdatalist->type = rdtype; + rdatalist->rdclass = rdclass; + +- dns_rdataset_init(rdataset); + result = dns_rdatalist_tordataset(rdatalist, rdataset); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); + + rdataset->attributes |= DNS_RDATASETATTR_QUESTION; + ++ /* ++ * Skip the duplicity check for first rdataset ++ */ ++ if (ISC_LIST_EMPTY(name->list)) { ++ result = ISC_R_SUCCESS; ++ goto skip_rds_check; ++ } ++ ++ /* ++ * Can't ask the same question twice. ++ */ ++ if (name->ht == NULL) { ++ isc_ht_init(&name->ht, msg->mctx, 1, ++ ISC_HT_CASE_SENSITIVE); ++ free_ht = true; ++ ++ INSIST(ISC_LIST_HEAD(name->list) == ++ ISC_LIST_TAIL(name->list)); ++ ++ dns_rdataset_t *old_rdataset = ++ ISC_LIST_HEAD(name->list); ++ ++ result = rds_hash_add(name->ht, old_rdataset, NULL); ++ ++ INSIST(result == ISC_R_SUCCESS); ++ } ++ result = rds_hash_add(name->ht, rdataset, NULL); ++ if (result == ISC_R_EXISTS) { ++ DO_ERROR(DNS_R_FORMERR); ++ } ++ ++ skip_rds_check: + ISC_LIST_APPEND(name->list, rdataset, link); ++ + rdataset = NULL; + } + + if (seen_problem) { +- return (DNS_R_RECOVERABLE); ++ result = DNS_R_RECOVERABLE; + } +- return (ISC_R_SUCCESS); + + cleanup: + if (rdataset != NULL) { +- INSIST(!dns_rdataset_isassociated(rdataset)); ++ if (dns_rdataset_isassociated(rdataset)) { ++ dns_rdataset_disassociate(rdataset); ++ } + isc_mempool_put(msg->rdspool, rdataset); + } + if (free_name) { + dns_message_puttempname(msg, &name); + } + ++ if (free_ht) { ++ cleanup_name_hashmaps(section); ++ } ++ ++ if (name_map != NULL) { ++ isc_ht_destroy(&name_map); ++ } ++ + return (result); + } + +@@ -1192,17 +1293,24 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + dns_name_t *name = NULL; + dns_name_t *name2 = NULL; + dns_rdataset_t *rdataset = NULL; ++ dns_rdataset_t *found_rdataset = NULL; + dns_rdatalist_t *rdatalist = NULL; +- isc_result_t result; ++ isc_result_t result = ISC_R_SUCCESS; + dns_rdatatype_t rdtype, covers; + dns_rdataclass_t rdclass; + dns_rdata_t *rdata = NULL; + dns_ttl_t ttl; + dns_namelist_t *section = &msg->sections[sectionid]; +- bool free_name = false, free_rdataset = false, seen_problem = false; ++ bool free_name = false, seen_problem = false; ++ bool free_ht = false; + bool preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0); + bool best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0); + bool isedns, issigzero, istsig; ++ isc_ht_t *name_map = NULL; ++ ++ if (msg->counts[sectionid] > 1) { ++ isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE); ++ } + + for (count = 0; count < msg->counts[sectionid]; count++) { + int recstart = source->current; +@@ -1210,10 +1318,10 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + + skip_name_search = false; + skip_type_search = false; +- free_rdataset = false; + isedns = false; + issigzero = false; + istsig = false; ++ found_rdataset = NULL; + + name = NULL; + result = dns_message_gettempname(msg, &name); +@@ -1253,8 +1361,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + if (msg->rdclass_set == 0 && + rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ + rdtype != dns_rdatatype_tsig && /* class is ANY */ +- rdtype != dns_rdatatype_tkey) +- { /* class is undefined */ ++ rdtype != dns_rdatatype_tkey) /* class is undefined */ ++ { + msg->rdclass = rdclass; + msg->rdclass_set = 1; + } +@@ -1360,10 +1468,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + * Then put the meta-class back into the finished rdata. + */ + rdata = newrdata(msg); +- if (rdata == NULL) { +- result = ISC_R_NOMEMORY; +- goto cleanup; +- } + if (msg->opcode == dns_opcode_update && + update(sectionid, rdclass)) { + if (rdatalen != 0) { +@@ -1446,33 +1550,72 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + free_name = false; + } + } else { ++ if (name_map == NULL) { ++ result = ISC_R_SUCCESS; ++ goto skip_name_check; ++ } ++ + /* + * Run through the section, looking to see if this name + * is already there. If it is found, put back the + * allocated name since we no longer need it, and set + * our name pointer to point to the name we found. + */ +- result = findname(&name2, name, section); ++ result = name_hash_add(name_map, name, &name2); + + /* + * If it is a new name, append to the section. + */ +- if (result == ISC_R_SUCCESS) { ++ skip_name_check: ++ switch (result) { ++ case ISC_R_SUCCESS: ++ ISC_LIST_APPEND(*section, name, link); ++ break; ++ case ISC_R_EXISTS: + dns_message_puttempname(msg, &name); + name = name2; +- } else { +- ISC_LIST_APPEND(*section, name, link); ++ name2 = NULL; ++ break; ++ default: ++ INSIST(0); ++ ISC_UNREACHABLE(); + } + free_name = false; + } + ++ rdatalist = newrdatalist(msg); ++ if (rdatalist == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto cleanup; ++ } ++ dns_message_gettemprdataset(msg, &rdataset); ++ if (rdataset == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto cleanup; ++ } ++ ++ rdatalist->type = rdtype; ++ rdatalist->covers = covers; ++ rdatalist->rdclass = rdclass; ++ rdatalist->ttl = ttl; ++ ++ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ++ ISC_R_SUCCESS); ++ dns_rdataset_setownercase(rdataset, name); ++ rdatalist = NULL; ++ + /* + * Search name for the particular type and class. + * Skip this stage if in update mode or this is a meta-type. + */ +- if (preserve_order || msg->opcode == dns_opcode_update || +- skip_type_search) { +- result = ISC_R_NOTFOUND; ++ if (isedns || istsig || issigzero) { ++ /* Skip adding the rdataset to the tables */ ++ } else if (preserve_order || msg->opcode == dns_opcode_update || ++ skip_type_search) ++ { ++ result = ISC_R_SUCCESS; ++ ++ ISC_LIST_APPEND(name->list, rdataset, link); + } else { + /* + * If this is a type that can only occur in +@@ -1482,63 +1625,72 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + DO_ERROR(DNS_R_FORMERR); + } + +- rdataset = NULL; +- result = dns_message_find(name, rdclass, rdtype, covers, +- &rdataset); +- } +- +- /* +- * If we found an rdataset that matches, we need to +- * append this rdata to that set. If we did not, we need +- * to create a new rdatalist, store the important bits there, +- * convert it to an rdataset, and link the latter to the name. +- * Yuck. When appending, make certain that the type isn't +- * a singleton type, such as SOA or CNAME. +- * +- * Note that this check will be bypassed when preserving order, +- * the opcode is an update, or the type search is skipped. +- */ +- if (result == ISC_R_SUCCESS) { +- if (dns_rdatatype_issingleton(rdtype)) { +- dns_rdata_t *first; +- dns_rdatalist_fromrdataset(rdataset, +- &rdatalist); +- first = ISC_LIST_HEAD(rdatalist->rdata); +- INSIST(first != NULL); +- if (dns_rdata_compare(rdata, first) != 0) { +- DO_ERROR(DNS_R_FORMERR); +- } ++ if (ISC_LIST_EMPTY(name->list)) { ++ result = ISC_R_SUCCESS; ++ goto skip_rds_check; + } +- } + +- if (result == ISC_R_NOTFOUND) { +- rdataset = isc_mempool_get(msg->rdspool); +- if (rdataset == NULL) { +- result = ISC_R_NOMEMORY; +- goto cleanup; +- } +- free_rdataset = true; ++ if (name->ht == NULL) { ++ isc_ht_init(&name->ht, msg->mctx, 1, ++ ISC_HT_CASE_SENSITIVE); ++ free_ht = true; + +- rdatalist = newrdatalist(msg); +- if (rdatalist == NULL) { +- result = ISC_R_NOMEMORY; +- goto cleanup; ++ INSIST(ISC_LIST_HEAD(name->list) == ++ ISC_LIST_TAIL(name->list)); ++ ++ dns_rdataset_t *old_rdataset = ++ ISC_LIST_HEAD(name->list); ++ ++ result = rds_hash_add(name->ht, old_rdataset, ++ NULL); ++ ++ INSIST(result == ISC_R_SUCCESS); + } ++ found_rdataset = NULL; ++ result = rds_hash_add(name->ht, rdataset, ++ &found_rdataset); + +- rdatalist->type = rdtype; +- rdatalist->covers = covers; +- rdatalist->rdclass = rdclass; +- rdatalist->ttl = ttl; ++ /* ++ * If we found an rdataset that matches, we need to ++ * append this rdata to that set. If we did not, we ++ * need to create a new rdatalist, store the important ++ * bits there, convert it to an rdataset, and link the ++ * latter to the name. Yuck. When appending, make ++ * certain that the type isn't a singleton type, such as ++ * SOA or CNAME. ++ * ++ * Note that this check will be bypassed when preserving ++ * order, the opcode is an update, or the type search is ++ * skipped. ++ */ ++ skip_rds_check: ++ switch (result) { ++ case ISC_R_EXISTS: ++ /* Free the rdataset we used as the key */ ++ dns_rdataset_disassociate(rdataset); ++ isc_mempool_put(msg->rdspool, rdataset); ++ result = ISC_R_SUCCESS; ++ rdataset = found_rdataset; + +- dns_rdataset_init(rdataset); +- RUNTIME_CHECK( +- dns_rdatalist_tordataset(rdatalist, rdataset) == +- ISC_R_SUCCESS); +- dns_rdataset_setownercase(rdataset, name); ++ if (!dns_rdatatype_issingleton(rdtype)) { ++ break; ++ } + +- if (!isedns && !istsig && !issigzero) { ++ dns_rdatalist_fromrdataset(rdataset, ++ &rdatalist); ++ dns_rdata_t *first = ++ ISC_LIST_HEAD(rdatalist->rdata); ++ INSIST(first != NULL); ++ if (dns_rdata_compare(rdata, first) != 0) { ++ DO_ERROR(DNS_R_FORMERR); ++ } ++ break; ++ case ISC_R_SUCCESS: + ISC_LIST_APPEND(name->list, rdataset, link); +- free_rdataset = false; ++ break; ++ default: ++ INSIST(0); ++ ISC_UNREACHABLE(); + } + } + +@@ -1573,8 +1725,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + dns_rcode_t ercode; + + msg->opt = rdataset; +- rdataset = NULL; +- free_rdataset = false; + ercode = (dns_rcode_t)((msg->opt->ttl & + DNS_MESSAGE_EDNSRCODE_MASK) >> + 20); +@@ -1585,8 +1735,6 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + msg->sig0 = rdataset; + msg->sig0name = name; + msg->sigstart = recstart; +- rdataset = NULL; +- free_rdataset = false; + free_name = false; + } else if (istsig) { + msg->tsig = rdataset; +@@ -1596,22 +1744,17 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + * Windows doesn't like TSIG names to be compressed. + */ + msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS; +- rdataset = NULL; +- free_rdataset = false; + free_name = false; + } ++ rdataset = NULL; + + if (seen_problem) { + if (free_name) { + dns_message_puttempname(msg, &name); + } +- if (free_rdataset) { +- isc_mempool_put(msg->rdspool, rdataset); +- } +- free_name = free_rdataset = false; ++ free_name = false; + } + INSIST(!free_name); +- INSIST(!free_rdataset); + } + + /* +@@ -1629,16 +1772,24 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + } + + if (seen_problem) { +- return (DNS_R_RECOVERABLE); ++ result = DNS_R_RECOVERABLE; + } +- return (ISC_R_SUCCESS); + + cleanup: ++ if (rdataset != NULL && rdataset != found_rdataset) { ++ dns_rdataset_disassociate(rdataset); ++ isc_mempool_put(msg->rdspool, rdataset); ++ } + if (free_name) { + dns_message_puttempname(msg, &name); + } +- if (free_rdataset) { +- isc_mempool_put(msg->rdspool, rdataset); ++ ++ if (free_ht) { ++ cleanup_name_hashmaps(section); ++ } ++ ++ if (name_map != NULL) { ++ isc_ht_destroy(&name_map); + } + + return (result); +@@ -2432,7 +2583,7 @@ dns_message_findname(dns_message_t *msg, dns_section_t section, + const dns_name_t *target, dns_rdatatype_t type, + dns_rdatatype_t covers, dns_name_t **name, + dns_rdataset_t **rdataset) { +- dns_name_t *foundname; ++ dns_name_t *foundname = NULL; + isc_result_t result; + + /* +@@ -2586,6 +2737,10 @@ dns_message_puttempname(dns_message_t *msg, dns_name_t **itemp) { + REQUIRE(!ISC_LINK_LINKED(item, link)); + REQUIRE(ISC_LIST_HEAD(item->list) == NULL); + ++ if (item->ht != NULL) { ++ isc_ht_destroy(&item->ht); ++ } ++ + /* + * we need to check this in case dns_name_dup() was used. + */ +diff --git a/lib/dns/name.c b/lib/dns/name.c +index 6ca311d..cc1b872 100644 +--- a/lib/dns/name.c ++++ b/lib/dns/name.c +@@ -186,6 +186,7 @@ dns_name_invalidate(dns_name_t *name) { + name->offsets = NULL; + name->buffer = NULL; + ISC_LINK_INIT(name, link); ++ INSIST(name->ht == NULL); + } + + bool +diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c +index 13cfc85..58f98a5 100644 +--- a/lib/dns/rpz.c ++++ b/lib/dns/rpz.c +@@ -1541,7 +1541,7 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { + * simplifies update_from_db + */ + +- isc_ht_init(&zone->nodes, rpzs->mctx, 1); ++ isc_ht_init(&zone->nodes, rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE); + + dns_name_init(&zone->origin, NULL); + dns_name_init(&zone->client_ip, NULL); +@@ -1718,7 +1718,8 @@ setup_update(dns_rpz_zone_t *rpz) { + ISC_LOG_DEBUG(1), "rpz: %s: using hashtable size %d", + domain, hashsize); + +- isc_ht_init(&rpz->newnodes, rpz->rpzs->mctx, hashsize); ++ isc_ht_init(&rpz->newnodes, rpz->rpzs->mctx, hashsize, ++ ISC_HT_CASE_SENSITIVE); + + result = dns_db_createiterator(rpz->updb, DNS_DB_NONSEC3, &rpz->updbit); + if (result != ISC_R_SUCCESS) { +diff --git a/lib/isc/ht.c b/lib/isc/ht.c +index 88e8578..c810ff1 100644 +--- a/lib/isc/ht.c ++++ b/lib/isc/ht.c +@@ -25,51 +25,274 @@ typedef struct isc_ht_node isc_ht_node_t; + #define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b') + #define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC) + ++#define HT_NO_BITS 0 ++#define HT_MIN_BITS 1 ++#define HT_MAX_BITS 32 ++#define HT_OVERCOMMIT 3 ++ ++#define HT_NEXTTABLE(idx) ((idx == 0) ? 1 : 0) ++#define TRY_NEXTTABLE(idx, ht) (idx == ht->hindex && rehashing_in_progress(ht)) ++ ++#define GOLDEN_RATIO_32 0x61C88647 ++ ++#define HASHSIZE(bits) (UINT64_C(1) << (bits)) ++ + struct isc_ht_node { + void *value; + isc_ht_node_t *next; ++ uint32_t hashval; + size_t keysize; +- unsigned char key[FLEXIBLE_ARRAY_MEMBER]; ++ unsigned char key[]; + }; + + struct isc_ht { + unsigned int magic; + isc_mem_t *mctx; +- size_t size; +- size_t mask; +- unsigned int count; +- isc_ht_node_t **table; ++ size_t count; ++ bool case_sensitive; ++ size_t size[2]; ++ uint8_t hashbits[2]; ++ isc_ht_node_t **table[2]; ++ uint8_t hindex; ++ uint32_t hiter; /* rehashing iterator */ + }; + + struct isc_ht_iter { + isc_ht_t *ht; + size_t i; ++ uint8_t hindex; + isc_ht_node_t *cur; + }; + ++static isc_ht_node_t * ++isc__ht_find(const isc_ht_t *ht, const unsigned char *key, ++ const uint32_t keysize, const uint32_t hashval, const uint8_t idx); ++static void ++isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, ++ const uint32_t hashval, const uint8_t idx, void *value); ++static isc_result_t ++isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, ++ const uint32_t hashval, const uint8_t idx); ++ ++static uint32_t ++rehash_bits(isc_ht_t *ht, size_t newcount); ++ ++static void ++hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits); ++static void ++hashtable_free(isc_ht_t *ht, const uint8_t idx); ++static void ++hashtable_rehash(isc_ht_t *ht, uint32_t newbits); ++static void ++hashtable_rehash_one(isc_ht_t *ht); ++static void ++maybe_rehash(isc_ht_t *ht, size_t newcount); ++ ++static isc_result_t ++isc__ht_iter_next(isc_ht_iter_t *it); ++ ++static uint8_t maptolower[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, ++ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, ++ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, ++ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, ++ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, ++ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, ++ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, ++ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, ++ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, ++ 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, ++ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, ++ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, ++ 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, ++ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, ++ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, ++ 0xfc, 0xfd, 0xfe, 0xff ++}; ++ ++static int ++memcasecmp(const void *vs1, const void *vs2, size_t len) { ++ uint8_t const *s1 = vs1; ++ uint8_t const *s2 = vs2; ++ for (size_t i = 0; i < len; i++) { ++ uint8_t u1 = s1[i]; ++ uint8_t u2 = s2[i]; ++ int U1 = maptolower[u1]; ++ int U2 = maptolower[u2]; ++ int diff = U1 - U2; ++ if (diff) { ++ return diff; ++ } ++ } ++ return 0; ++} ++ ++static bool ++isc__ht_node_match(isc_ht_node_t *node, const uint32_t hashval, ++ const uint8_t *key, uint32_t keysize, bool case_sensitive) { ++ return (node->hashval == hashval && node->keysize == keysize && ++ (case_sensitive ? (memcmp(node->key, key, keysize) == 0) ++ : (memcasecmp(node->key, key, keysize) == 0))); ++} ++ ++static uint32_t ++hash_32(uint32_t val, unsigned int bits) { ++ REQUIRE(bits <= HT_MAX_BITS); ++ /* High bits are more random. */ ++ return (val * GOLDEN_RATIO_32 >> (32 - bits)); ++} ++ ++static bool ++rehashing_in_progress(const isc_ht_t *ht) { ++ return (ht->table[HT_NEXTTABLE(ht->hindex)] != NULL); ++} ++ ++static bool ++hashtable_is_overcommited(isc_ht_t *ht) { ++ return (ht->count >= (ht->size[ht->hindex] * HT_OVERCOMMIT)); ++} ++ ++static uint32_t ++rehash_bits(isc_ht_t *ht, size_t newcount) { ++ uint32_t newbits = ht->hashbits[ht->hindex]; ++ ++ while (newcount >= HASHSIZE(newbits) && newbits <= HT_MAX_BITS) { ++ newbits += 1; ++ } ++ ++ return (newbits); ++} ++ ++/* ++ * Rebuild the hashtable to reduce the load factor ++ */ ++static void ++hashtable_rehash(isc_ht_t *ht, uint32_t newbits) { ++ uint8_t oldindex = ht->hindex; ++ uint32_t oldbits = ht->hashbits[oldindex]; ++ uint8_t newindex = HT_NEXTTABLE(oldindex); ++ ++ REQUIRE(ht->hashbits[oldindex] >= HT_MIN_BITS); ++ REQUIRE(ht->hashbits[oldindex] <= HT_MAX_BITS); ++ REQUIRE(ht->table[oldindex] != NULL); ++ ++ REQUIRE(newbits <= HT_MAX_BITS); ++ REQUIRE(ht->hashbits[newindex] == HT_NO_BITS); ++ REQUIRE(ht->table[newindex] == NULL); ++ ++ REQUIRE(newbits > oldbits); ++ ++ hashtable_new(ht, newindex, newbits); ++ ++ ht->hindex = newindex; ++ ++ hashtable_rehash_one(ht); ++} ++ ++static void ++hashtable_rehash_one(isc_ht_t *ht) { ++ isc_ht_node_t **newtable = ht->table[ht->hindex]; ++ uint32_t oldsize = ht->size[HT_NEXTTABLE(ht->hindex)]; ++ isc_ht_node_t **oldtable = ht->table[HT_NEXTTABLE(ht->hindex)]; ++ isc_ht_node_t *node = NULL; ++ isc_ht_node_t *nextnode; ++ ++ /* Find first non-empty node */ ++ while (ht->hiter < oldsize && oldtable[ht->hiter] == NULL) { ++ ht->hiter++; ++ } ++ ++ /* Rehashing complete */ ++ if (ht->hiter == oldsize) { ++ hashtable_free(ht, HT_NEXTTABLE(ht->hindex)); ++ ht->hiter = 0; ++ return; ++ } ++ ++ /* Move the first non-empty node from old hashtable to new hashtable */ ++ for (node = oldtable[ht->hiter]; node != NULL; node = nextnode) { ++ uint32_t hash = hash_32(node->hashval, ++ ht->hashbits[ht->hindex]); ++ nextnode = node->next; ++ node->next = newtable[hash]; ++ newtable[hash] = node; ++ } ++ ++ oldtable[ht->hiter] = NULL; ++ ++ ht->hiter++; ++} ++ ++static void ++maybe_rehash(isc_ht_t *ht, size_t newcount) { ++ uint32_t newbits = rehash_bits(ht, newcount); ++ ++ if (ht->hashbits[ht->hindex] < newbits && newbits <= HT_MAX_BITS) { ++ hashtable_rehash(ht, newbits); ++ } ++} ++ ++static void ++hashtable_new(isc_ht_t *ht, const uint8_t idx, const uint8_t bits) { ++ size_t size; ++ REQUIRE(ht->hashbits[idx] == HT_NO_BITS); ++ REQUIRE(ht->table[idx] == NULL); ++ REQUIRE(bits >= HT_MIN_BITS); ++ REQUIRE(bits <= HT_MAX_BITS); ++ ++ ht->hashbits[idx] = bits; ++ ht->size[idx] = HASHSIZE(ht->hashbits[idx]); ++ ++ size = ht->size[idx] * sizeof(isc_ht_node_t *); ++ ++ ht->table[idx] = isc_mem_get(ht->mctx, size); ++ memset(ht->table[idx], 0, size); ++} ++ ++static void ++hashtable_free(isc_ht_t *ht, const uint8_t idx) { ++ size_t size = ht->size[idx] * sizeof(isc_ht_node_t *); ++ ++ for (size_t i = 0; i < ht->size[idx]; i++) { ++ isc_ht_node_t *node = ht->table[idx][i]; ++ while (node != NULL) { ++ isc_ht_node_t *next = node->next; ++ ht->count--; ++ isc_mem_put(ht->mctx, node, ++ sizeof(*node) + node->keysize); ++ node = next; ++ } ++ } ++ ++ isc_mem_put(ht->mctx, ht->table[idx], size); ++ ht->hashbits[idx] = HT_NO_BITS; ++ ht->table[idx] = NULL; ++} ++ + void +-isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { ++isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits, ++ unsigned int options) { + isc_ht_t *ht = NULL; +- size_t i; ++ bool case_sensitive = ((options & ISC_HT_CASE_INSENSITIVE) == 0); + + REQUIRE(htp != NULL && *htp == NULL); + REQUIRE(mctx != NULL); +- REQUIRE(bits >= 1 && bits <= (sizeof(size_t) * 8 - 1)); ++ REQUIRE(bits >= 1 && bits <= HT_MAX_BITS); + +- ht = isc_mem_get(mctx, sizeof(struct isc_ht)); ++ ht = isc_mem_get(mctx, sizeof(*ht)); ++ *ht = (isc_ht_t){ ++ .case_sensitive = case_sensitive, ++ }; + +- ht->mctx = NULL; + isc_mem_attach(mctx, &ht->mctx); + +- ht->size = ((size_t)1 << bits); +- ht->mask = ((size_t)1 << bits) - 1; +- ht->count = 0; +- +- ht->table = isc_mem_get(ht->mctx, ht->size * sizeof(isc_ht_node_t *)); +- +- for (i = 0; i < ht->size; i++) { +- ht->table[i] = NULL; +- } ++ hashtable_new(ht, 0, bits); + + ht->magic = ISC_HT_MAGIC; + +@@ -79,125 +302,188 @@ isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { + void + isc_ht_destroy(isc_ht_t **htp) { + isc_ht_t *ht; +- size_t i; + + REQUIRE(htp != NULL); ++ REQUIRE(ISC_HT_VALID(*htp)); + + ht = *htp; + *htp = NULL; +- +- REQUIRE(ISC_HT_VALID(ht)); +- + ht->magic = 0; + +- for (i = 0; i < ht->size; i++) { +- isc_ht_node_t *node = ht->table[i]; +- while (node != NULL) { +- isc_ht_node_t *next = node->next; +- ht->count--; +- isc_mem_put(ht->mctx, node, +- offsetof(isc_ht_node_t, key) + +- node->keysize); +- node = next; ++ for (size_t i = 0; i <= 1; i++) { ++ if (ht->table[i] != NULL) { ++ hashtable_free(ht, i); + } + } + + INSIST(ht->count == 0); + +- isc_mem_put(ht->mctx, ht->table, ht->size * sizeof(isc_ht_node_t *)); +- isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht)); ++ isc_mem_putanddetach(&ht->mctx, ht, sizeof(*ht)); + } + +-isc_result_t +-isc_ht_add(isc_ht_t *ht, const unsigned char *key, uint32_t keysize, +- void *value) { ++static void ++isc__ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, ++ const uint32_t hashval, const uint8_t idx, void *value) { ++ + isc_ht_node_t *node; + uint32_t hash; ++ hash = hash_32(hashval, ht->hashbits[idx]); ++ ++ node = isc_mem_get(ht->mctx, sizeof(*node) + keysize); ++ *node = (isc_ht_node_t){ ++ .keysize = keysize, ++ .hashval = hashval, ++ .next = ht->table[idx][hash], ++ .value = value, ++ }; ++ ++ memmove(node->key, key, keysize); ++ ++ ht->count++; ++ ht->table[idx][hash] = node; ++} ++ ++isc_result_t ++isc_ht_add(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, ++ void *value) { ++ uint32_t hashval; + + REQUIRE(ISC_HT_VALID(ht)); + REQUIRE(key != NULL && keysize > 0); +- +- hash = isc_hash_function(key, keysize, true); +- node = ht->table[hash & ht->mask]; +- while (node != NULL) { +- if (keysize == node->keysize && +- memcmp(key, node->key, keysize) == 0) { +- return (ISC_R_EXISTS); +- } +- node = node->next; ++ if (rehashing_in_progress(ht)) { ++ /* Rehash in progress */ ++ hashtable_rehash_one(ht); ++ } else if (hashtable_is_overcommited(ht)) { ++ /* Rehash requested */ ++ maybe_rehash(ht, ht->count); + } + +- node = isc_mem_get(ht->mctx, offsetof(isc_ht_node_t, key) + keysize); ++ hashval = isc_hash32(key, keysize, ht->case_sensitive); + +- memmove(node->key, key, keysize); +- node->keysize = keysize; +- node->next = ht->table[hash & ht->mask]; +- node->value = value; ++ if (isc__ht_find(ht, key, keysize, hashval, ht->hindex) != NULL) { ++ return (ISC_R_EXISTS); ++ } ++ ++ isc__ht_add(ht, key, keysize, hashval, ht->hindex, value); + +- ht->count++; +- ht->table[hash & ht->mask] = node; + return (ISC_R_SUCCESS); + } + ++static isc_ht_node_t * ++isc__ht_find(const isc_ht_t *ht, const unsigned char *key, ++ const uint32_t keysize, const uint32_t hashval, ++ const uint8_t idx) { ++ uint32_t hash; ++ uint8_t findex = idx; ++ ++nexttable: ++ hash = hash_32(hashval, ht->hashbits[findex]); ++ for (isc_ht_node_t *node = ht->table[findex][hash]; node != NULL; ++ node = node->next) ++ { ++ if (isc__ht_node_match(node, hashval, key, keysize, ++ ht->case_sensitive)) ++ { ++ return (node); ++ } ++ } ++ if (TRY_NEXTTABLE(findex, ht)) { ++ /* ++ * Rehashing in progress, check the other table ++ */ ++ findex = HT_NEXTTABLE(findex); ++ goto nexttable; ++ } ++ ++ return (NULL); ++} ++ ++ + isc_result_t +-isc_ht_find(const isc_ht_t *ht, const unsigned char *key, uint32_t keysize, +- void **valuep) { ++isc_ht_find(const isc_ht_t *ht, const unsigned char *key, ++ const uint32_t keysize, void **valuep) { ++ uint32_t hashval; ++ + isc_ht_node_t *node; +- uint32_t hash; + + REQUIRE(ISC_HT_VALID(ht)); + REQUIRE(key != NULL && keysize > 0); + REQUIRE(valuep == NULL || *valuep == NULL); + +- hash = isc_hash_function(key, keysize, true); +- node = ht->table[hash & ht->mask]; +- while (node != NULL) { +- if (keysize == node->keysize && +- memcmp(key, node->key, keysize) == 0) { +- if (valuep != NULL) { +- *valuep = node->value; +- } +- return (ISC_R_SUCCESS); +- } +- node = node->next; ++ hashval = isc_hash32(key, keysize, ht->case_sensitive); ++ ++ node = isc__ht_find(ht, key, keysize, hashval, ht->hindex); ++ if (node == NULL) { ++ return (ISC_R_NOTFOUND); + } + +- return (ISC_R_NOTFOUND); ++ if (valuep != NULL) { ++ *valuep = node->value; ++ } ++ return (ISC_R_SUCCESS); + } + +-isc_result_t +-isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize) { +- isc_ht_node_t *node, *prev; ++static isc_result_t ++isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize, ++ const uint32_t hashval, const uint8_t idx) { ++ isc_ht_node_t *prev = NULL; + uint32_t hash; + +- REQUIRE(ISC_HT_VALID(ht)); +- REQUIRE(key != NULL && keysize > 0); ++ hash = hash_32(hashval, ht->hashbits[idx]); + +- prev = NULL; +- hash = isc_hash_function(key, keysize, true); +- node = ht->table[hash & ht->mask]; +- while (node != NULL) { +- if (keysize == node->keysize && +- memcmp(key, node->key, keysize) == 0) { ++ for (isc_ht_node_t *node = ht->table[idx][hash]; node != NULL; ++ prev = node, node = node->next) ++ { ++ if (isc__ht_node_match(node, hashval, key, keysize, ++ ht->case_sensitive)) ++ { + if (prev == NULL) { +- ht->table[hash & ht->mask] = node->next; ++ ht->table[idx][hash] = node->next; + } else { + prev->next = node->next; + } + isc_mem_put(ht->mctx, node, +- offsetof(isc_ht_node_t, key) + +- node->keysize); ++ sizeof(*node) + node->keysize); + ht->count--; + + return (ISC_R_SUCCESS); + } + +- prev = node; +- node = node->next; + } ++ + return (ISC_R_NOTFOUND); + } + ++isc_result_t ++isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize) { ++ uint32_t hashval; ++ uint8_t hindex; ++ isc_result_t result; ++ ++ REQUIRE(ISC_HT_VALID(ht)); ++ REQUIRE(key != NULL && keysize > 0); ++ ++ if (rehashing_in_progress(ht)) { ++ /* Rehash in progress */ ++ hashtable_rehash_one(ht); ++ } ++ ++ hindex = ht->hindex; ++ hashval = isc_hash32(key, keysize, ht->case_sensitive); ++nexttable: ++ result = isc__ht_delete(ht, key, keysize, hashval, hindex); ++ ++ if (result == ISC_R_NOTFOUND && TRY_NEXTTABLE(hindex, ht)) { ++ /* ++ * Rehashing in progress, check the other table ++ */ ++ hindex = HT_NEXTTABLE(hindex); ++ goto nexttable; ++ } ++ ++ return (result); ++} ++ + void + isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { + isc_ht_iter_t *it; +@@ -206,10 +492,10 @@ isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { + REQUIRE(itp != NULL && *itp == NULL); + + it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t)); +- +- it->ht = ht; +- it->i = 0; +- it->cur = NULL; ++ *it = (isc_ht_iter_t){ ++ .ht = ht, ++ .hindex = ht->hindex, ++ }; + + *itp = it; + } +@@ -224,25 +510,46 @@ isc_ht_iter_destroy(isc_ht_iter_t **itp) { + it = *itp; + *itp = NULL; + ht = it->ht; +- isc_mem_put(ht->mctx, it, sizeof(isc_ht_iter_t)); ++ isc_mem_put(ht->mctx, it, sizeof(*it)); + } + + isc_result_t + isc_ht_iter_first(isc_ht_iter_t *it) { ++ isc_ht_t *ht; ++ + REQUIRE(it != NULL); + ++ ht = it->ht; ++ ++ it->hindex = ht->hindex; + it->i = 0; +- while (it->i < it->ht->size && it->ht->table[it->i] == NULL) { ++ ++ return (isc__ht_iter_next(it)); ++} ++ ++static isc_result_t ++isc__ht_iter_next(isc_ht_iter_t *it) { ++ isc_ht_t *ht = it->ht; ++ ++ while (it->i < ht->size[it->hindex] && ++ ht->table[it->hindex][it->i] == NULL) ++ { + it->i++; + } + +- if (it->i == it->ht->size) { +- return (ISC_R_NOMORE); ++ if (it->i < ht->size[it->hindex]) { ++ it->cur = ht->table[it->hindex][it->i]; ++ ++ return (ISC_R_SUCCESS); + } + +- it->cur = it->ht->table[it->i]; ++ if (TRY_NEXTTABLE(it->hindex, ht)) { ++ it->hindex = HT_NEXTTABLE(it->hindex); ++ it->i = 0; ++ return (isc__ht_iter_next(it)); ++ } + +- return (ISC_R_SUCCESS); ++ return (ISC_R_NOMORE); + } + + isc_result_t +@@ -251,60 +558,36 @@ isc_ht_iter_next(isc_ht_iter_t *it) { + REQUIRE(it->cur != NULL); + + it->cur = it->cur->next; +- if (it->cur == NULL) { +- do { +- it->i++; +- } while (it->i < it->ht->size && it->ht->table[it->i] == NULL); +- if (it->i >= it->ht->size) { +- return (ISC_R_NOMORE); +- } +- it->cur = it->ht->table[it->i]; ++ ++ if (it->cur != NULL) { ++ return (ISC_R_SUCCESS); + } + +- return (ISC_R_SUCCESS); ++ it->i++; ++ ++ return (isc__ht_iter_next(it)); + } + + isc_result_t + isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) { + isc_result_t result = ISC_R_SUCCESS; +- isc_ht_node_t *to_delete = NULL; +- isc_ht_node_t *prev = NULL; +- isc_ht_node_t *node = NULL; +- uint32_t hash; ++ isc_ht_node_t *dnode = NULL; ++ uint8_t dindex; + isc_ht_t *ht; ++ isc_result_t dresult; ++ + REQUIRE(it != NULL); + REQUIRE(it->cur != NULL); +- to_delete = it->cur; +- ht = it->ht; + +- it->cur = it->cur->next; +- if (it->cur == NULL) { +- do { +- it->i++; +- } while (it->i < ht->size && ht->table[it->i] == NULL); +- if (it->i >= ht->size) { +- result = ISC_R_NOMORE; +- } else { +- it->cur = ht->table[it->i]; +- } +- } ++ ht = it->ht; ++ dnode = it->cur; ++ dindex = it->hindex; + +- hash = isc_hash_function(to_delete->key, to_delete->keysize, true); +- node = ht->table[hash & ht->mask]; +- while (node != to_delete) { +- prev = node; +- node = node->next; +- INSIST(node != NULL); +- } ++ result = isc_ht_iter_next(it); + +- if (prev == NULL) { +- ht->table[hash & ht->mask] = node->next; +- } else { +- prev->next = node->next; +- } +- isc_mem_put(ht->mctx, node, +- offsetof(isc_ht_node_t, key) + node->keysize); +- ht->count--; ++ dresult = isc__ht_delete(ht, dnode->key, dnode->keysize, dnode->hashval, ++ dindex); ++ INSIST(dresult == ISC_R_SUCCESS); + + return (result); + } +@@ -329,8 +612,8 @@ isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, + *keysize = it->cur->keysize; + } + +-unsigned int +-isc_ht_count(isc_ht_t *ht) { ++size_t ++isc_ht_count(const isc_ht_t *ht) { + REQUIRE(ISC_HT_VALID(ht)); + + return (ht->count); +diff --git a/lib/isc/include/isc/ht.h b/lib/isc/include/isc/ht.h +index 280ee7e..0714875 100644 +--- a/lib/isc/include/isc/ht.h ++++ b/lib/isc/include/isc/ht.h +@@ -11,8 +11,7 @@ + + /* ! \file */ + +-#ifndef ISC_HT_H +-#define ISC_HT_H 1 ++#pragma once + + #include + #include +@@ -23,9 +22,15 @@ + typedef struct isc_ht isc_ht_t; + typedef struct isc_ht_iter isc_ht_iter_t; + ++enum { ISC_HT_CASE_SENSITIVE = 0x00, ISC_HT_CASE_INSENSITIVE = 0x01 }; ++ + /*% + * Initialize hashtable at *htp, using memory context and size of (1< +Date: Thu, 11 Jan 2024 12:03:24 +0100 +Subject: [PATCH] Split fast and slow task queues + +Change the taskmgr (and thus netmgr) in a way that it supports fast and +slow task queues. The fast queue is used for incoming DNS traffic and +it will pass the processing to the slow queue for sending outgoing DNS +messages and processing resolver messages. + +In the future, more tasks might get moved to the slow queues, so the +cached and authoritative DNS traffic can be handled without being slowed +down by operations that take longer time to process. + +Conflict:Since the optimization patch 32a3970b has not been incorporated, the patch test modification part needs to be incorporated. +Reference:https://downloads.isc.org/isc/bind/9.16.48/patches/0005-CVE-2023-50387-CVE-2023-50868.patch + +(cherry picked from commit 1b3b0cef224e7a9e8279c5cfe2f7e188e3777cc7) + +--- + lib/dns/dst_api.c | 27 +++++++++---- + lib/dns/include/dns/validator.h | 1 + + lib/dns/include/dst/dst.h | 4 ++ + lib/dns/resolver.c | 4 +- + lib/dns/validator.c | 67 +++++++++++++++------------------ + lib/isc/include/isc/netmgr.h | 3 ++ + lib/isc/netmgr/netmgr-int.h | 1 + + lib/isc/netmgr/netmgr.c | 36 +++++++++++------- + lib/isc/netmgr/tcp.c | 6 +-- + lib/isc/netmgr/tcpdns.c | 4 +- + lib/isc/netmgr/udp.c | 6 +-- + lib/isc/tests/netmgr_test.c | 2 - + 12 files changed, 91 insertions(+), 70 deletions(-) + +diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c +index c2977e0..0bf84b9 100644 +--- a/lib/dns/dst_api.c ++++ b/lib/dns/dst_api.c +@@ -160,7 +160,8 @@ computeid(dst_key_t *key); + static isc_result_t + frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, +- isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); ++ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, ++ dst_key_t **keyp); + + static isc_result_t + algorithm_status(unsigned int alg); +@@ -776,6 +777,13 @@ dst_key_todns(const dst_key_t *key, isc_buffer_t *target) { + isc_result_t + dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) { ++ return (dst_key_fromdns_ex(name, rdclass, source, mctx, false, keyp)); ++} ++ ++isc_result_t ++dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass, ++ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, ++ dst_key_t **keyp) { + uint8_t alg, proto; + uint32_t flags, extflags; + dst_key_t *key = NULL; +@@ -806,7 +814,7 @@ dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, + } + + result = frombuffer(name, alg, flags, proto, rdclass, source, mctx, +- &key); ++ no_rdata, &key); + if (result != ISC_R_SUCCESS) { + return (result); + } +@@ -827,7 +835,7 @@ dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, + REQUIRE(dst_initialized); + + result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx, +- &key); ++ false, &key); + if (result != ISC_R_SUCCESS) { + return (result); + } +@@ -2331,7 +2339,8 @@ computeid(dst_key_t *key) { + static isc_result_t + frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, + unsigned int protocol, dns_rdataclass_t rdclass, +- isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) { ++ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, ++ dst_key_t **keyp) { + dst_key_t *key; + isc_result_t ret; + +@@ -2356,10 +2365,12 @@ frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags, + return (DST_R_UNSUPPORTEDALG); + } + +- ret = key->func->fromdns(key, source); +- if (ret != ISC_R_SUCCESS) { +- dst_key_free(&key); +- return (ret); ++ if (!no_rdata) { ++ ret = key->func->fromdns(key, source); ++ if (ret != ISC_R_SUCCESS) { ++ dst_key_free(&key); ++ return (ret); ++ } + } + } + +diff --git a/lib/dns/include/dns/validator.h b/lib/dns/include/dns/validator.h +index 4744014..73ac1cd 100644 +--- a/lib/dns/include/dns/validator.h ++++ b/lib/dns/include/dns/validator.h +@@ -147,6 +147,7 @@ struct dns_validator { + unsigned int depth; + unsigned int authcount; + unsigned int authfail; ++ bool failed; + isc_stdtime_t start; + }; + +diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h +index df48d8e..46fb193 100644 +--- a/lib/dns/include/dst/dst.h ++++ b/lib/dns/include/dst/dst.h +@@ -469,6 +469,10 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory); + */ + + isc_result_t ++dst_key_fromdns_ex(const dns_name_t *name, dns_rdataclass_t rdclass, ++ isc_buffer_t *source, isc_mem_t *mctx, bool no_rdata, ++ dst_key_t **keyp); ++isc_result_t + dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass, + isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp); + /*%< +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 5f31d5b..cc8c9ab 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -10559,8 +10559,8 @@ dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, + * Since we have a pool of tasks we bind them to task queues + * to spread the load evenly + */ +- result = isc_task_create_bound(taskmgr, 0, +- &res->buckets[i].task, i); ++ result = isc_task_create_bound( ++ taskmgr, 0, &res->buckets[i].task, ISC_NM_TASK_SLOW(i)); + if (result != ISC_R_SUCCESS) { + isc_mutex_destroy(&res->buckets[i].lock); + goto cleanup_buckets; +diff --git a/lib/dns/validator.c b/lib/dns/validator.c +index e54fc70..e416cc9 100644 +--- a/lib/dns/validator.c ++++ b/lib/dns/validator.c +@@ -1098,8 +1098,8 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, + * 'rdataset'. If found, build a dst_key_t for it and point val->key at + * it. + * +- * If val->key is already non-NULL, locate it in the rdataset and then +- * search past it for the *next* key that could have signed 'siginfo', then ++ * If val->key is already non-NULL, start searching from the next position in ++ * 'rdataset' to find the *next* key that could have signed 'siginfo', then + * set val->key to that. + * + * Returns ISC_R_SUCCESS if a possible matching key has been found, +@@ -1112,59 +1112,59 @@ select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) { + isc_buffer_t b; + dns_rdata_t rdata = DNS_RDATA_INIT; + dst_key_t *oldkey = val->key; +- bool foundold; ++ bool no_rdata = false; + + if (oldkey == NULL) { +- foundold = true; ++ result = dns_rdataset_first(rdataset); + } else { +- foundold = false; ++ dst_key_free(&oldkey); + val->key = NULL; ++ result = dns_rdataset_next(rdataset); + } +- +- result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS) { +- goto failure; ++ goto done; + } ++ + do { + dns_rdataset_current(rdataset, &rdata); + + isc_buffer_init(&b, rdata.data, rdata.length); + isc_buffer_add(&b, rdata.length); + INSIST(val->key == NULL); +- result = dst_key_fromdns(&siginfo->signer, rdata.rdclass, &b, +- val->view->mctx, &val->key); ++ result = dst_key_fromdns_ex(&siginfo->signer, rdata.rdclass, &b, ++ val->view->mctx, no_rdata, ++ &val->key); + if (result == ISC_R_SUCCESS) { + if (siginfo->algorithm == + (dns_secalg_t)dst_key_alg(val->key) && + siginfo->keyid == + (dns_keytag_t)dst_key_id(val->key) && ++ (dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) == ++ 0 && + dst_key_iszonekey(val->key)) + { +- if (foundold) { +- /* +- * This is the key we're looking for. +- */ +- return (ISC_R_SUCCESS); +- } else if (dst_key_compare(oldkey, val->key)) { +- foundold = true; +- dst_key_free(&oldkey); ++ if (no_rdata) { ++ /* Retry with full key */ ++ dns_rdata_reset(&rdata); ++ dst_key_free(&val->key); ++ no_rdata = false; ++ continue; + } ++ /* This is the key we're looking for. */ ++ goto done; + } + dst_key_free(&val->key); + } + dns_rdata_reset(&rdata); + result = dns_rdataset_next(rdataset); ++ no_rdata = true; + } while (result == ISC_R_SUCCESS); + ++done: + if (result == ISC_R_NOMORE) { + result = ISC_R_NOTFOUND; + } + +-failure: +- if (oldkey != NULL) { +- dst_key_free(&oldkey); +- } +- + return (result); + } + +@@ -1557,20 +1557,9 @@ validate_answer(dns_validator_t *val, bool resume) { + continue; + } + +- do { +- isc_result_t tresult; +- vresult = verify(val, val->key, &rdata, +- val->siginfo->keyid); +- if (vresult == ISC_R_SUCCESS) { +- break; +- } +- +- tresult = select_signing_key(val, val->keyset); +- if (tresult != ISC_R_SUCCESS) { +- break; +- } +- } while (1); ++ vresult = verify(val, val->key, &rdata, val->siginfo->keyid); + if (vresult != ISC_R_SUCCESS) { ++ val->failed = true; + validator_log(val, ISC_LOG_DEBUG(3), + "failed to verify rdataset"); + } else { +@@ -1607,9 +1596,13 @@ validate_answer(dns_validator_t *val, bool resume) { + } else { + validator_log(val, ISC_LOG_DEBUG(3), + "verify failure: %s", +- isc_result_totext(result)); ++ isc_result_totext(vresult)); + resume = false; + } ++ if (val->failed) { ++ result = ISC_R_NOMORE; ++ break; ++ } + } + if (result != ISC_R_NOMORE) { + validator_log(val, ISC_LOG_DEBUG(3), +diff --git a/lib/isc/include/isc/netmgr.h b/lib/isc/include/isc/netmgr.h +index dc44ef2..1b88832 100644 +--- a/lib/isc/include/isc/netmgr.h ++++ b/lib/isc/include/isc/netmgr.h +@@ -455,6 +455,9 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, + * 'cb'. + */ + ++#define ISC_NM_TASK_SLOW_OFFSET -2 ++#define ISC_NM_TASK_SLOW(i) (ISC_NM_TASK_SLOW_OFFSET - 1 - i) ++ + void + isc_nm_task_enqueue(isc_nm_t *mgr, isc_task_t *task, int threadid); + /*%< +diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h +index 23bc2a2..80de758 100644 +--- a/lib/isc/netmgr/netmgr-int.h ++++ b/lib/isc/netmgr/netmgr-int.h +@@ -630,6 +630,7 @@ struct isc_nm { + isc_refcount_t references; + isc_mem_t *mctx; + int nworkers; ++ int nlisteners; + isc_mutex_t lock; + isc_condition_t wkstatecond; + isc_condition_t wkpausecond; +diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c +index 71c6d62..1aa249e 100644 +--- a/lib/isc/netmgr/netmgr.c ++++ b/lib/isc/netmgr/netmgr.c +@@ -272,31 +272,34 @@ isc__nm_winsock_destroy(void) { + #endif /* WIN32 */ + + static void +-isc__nm_threadpool_initialize(uint32_t workers) { ++isc__nm_threadpool_initialize(uint32_t nworkers) { + char buf[11]; + int r = uv_os_getenv("UV_THREADPOOL_SIZE", buf, + &(size_t){ sizeof(buf) }); + if (r == UV_ENOENT) { +- snprintf(buf, sizeof(buf), "%" PRIu32, workers); ++ snprintf(buf, sizeof(buf), "%" PRIu32, nworkers); + uv_os_setenv("UV_THREADPOOL_SIZE", buf); + } + } + + void +-isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { ++isc__netmgr_create(isc_mem_t *mctx, uint32_t nworkers, isc_nm_t **netmgrp) { + isc_nm_t *mgr = NULL; + char name[32]; + +- REQUIRE(workers > 0); ++ REQUIRE(nworkers > 0); + + #ifdef WIN32 + isc__nm_winsock_initialize(); + #endif /* WIN32 */ + +- isc__nm_threadpool_initialize(workers); ++ isc__nm_threadpool_initialize(nworkers); + + mgr = isc_mem_get(mctx, sizeof(*mgr)); +- *mgr = (isc_nm_t){ .nworkers = workers }; ++ *mgr = (isc_nm_t){ ++ .nworkers = nworkers * 2, ++ .nlisteners = nworkers, ++ }; + + isc_mem_attach(mctx, &mgr->mctx); + isc_mutex_init(&mgr->lock); +@@ -337,11 +340,12 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { + isc_mempool_associatelock(mgr->evpool, &mgr->evlock); + isc_mempool_setfillcount(mgr->evpool, 32); + +- isc_barrier_init(&mgr->pausing, workers); +- isc_barrier_init(&mgr->resuming, workers); ++ isc_barrier_init(&mgr->pausing, mgr->nworkers); ++ isc_barrier_init(&mgr->resuming, mgr->nworkers); + +- mgr->workers = isc_mem_get(mctx, workers * sizeof(isc__networker_t)); +- for (size_t i = 0; i < workers; i++) { ++ mgr->workers = isc_mem_get(mctx, ++ mgr->nworkers * sizeof(isc__networker_t)); ++ for (int i = 0; i < mgr->nworkers; i++) { + int r; + isc__networker_t *worker = &mgr->workers[i]; + *worker = (isc__networker_t){ +@@ -376,7 +380,7 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) { + mgr->workers_running++; + isc_thread_create(nm_thread, &mgr->workers[i], &worker->thread); + +- snprintf(name, sizeof(name), "isc-net-%04zu", i); ++ snprintf(name, sizeof(name), "isc-net-%04d", i); + isc_thread_setname(worker->thread, name); + } + +@@ -860,9 +864,15 @@ isc_nm_task_enqueue(isc_nm_t *nm, isc_task_t *task, int threadid) { + isc__networker_t *worker = NULL; + + if (threadid == -1) { +- tid = (int)isc_random_uniform(nm->nworkers); ++ tid = (int)isc_random_uniform(nm->nlisteners); ++ } else if (threadid == ISC_NM_TASK_SLOW_OFFSET) { ++ tid = nm->nlisteners + ++ (int)isc_random_uniform(nm->nworkers - nm->nlisteners); ++ } else if (threadid < ISC_NM_TASK_SLOW_OFFSET) { ++ tid = nm->nlisteners + (ISC_NM_TASK_SLOW(threadid) % ++ (nm->nworkers - nm->nlisteners)); + } else { +- tid = threadid % nm->nworkers; ++ tid = threadid % nm->nlisteners; + } + + worker = &nm->workers[tid]; +diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c +index dde592d..c2e059a 100644 +--- a/lib/isc/netmgr/tcp.c ++++ b/lib/isc/netmgr/tcp.c +@@ -321,7 +321,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, + isc__nm_connectcb(sock, req, result, false); + } else { + isc__nmsocket_clearcb(sock); +- sock->tid = isc_random_uniform(mgr->nworkers); ++ sock->tid = isc_random_uniform(mgr->nlisteners); + isc__nm_connectcb(sock, req, result, true); + } + atomic_store(&sock->closed, true); +@@ -339,7 +339,7 @@ isc_nm_tcpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, + isc__nm_put_netievent_tcpconnect(mgr, ievent); + } else { + atomic_init(&sock->active, false); +- sock->tid = isc_random_uniform(mgr->nworkers); ++ sock->tid = isc_random_uniform(mgr->nlisteners); + isc__nm_enqueue_ievent(&mgr->workers[sock->tid], + (isc__netievent_t *)ievent); + } +@@ -435,7 +435,7 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_sockaddr_t *iface, + #if defined(WIN32) + sock->nchildren = 1; + #else +- sock->nchildren = mgr->nworkers; ++ sock->nchildren = mgr->nlisteners; + #endif + children_size = sock->nchildren * sizeof(sock->children[0]); + sock->children = isc_mem_get(mgr->mctx, children_size); +diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c +index f66944e..8f79a7f 100644 +--- a/lib/isc/netmgr/tcpdns.c ++++ b/lib/isc/netmgr/tcpdns.c +@@ -301,7 +301,7 @@ isc_nm_tcpdnsconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, + isc__nm_put_netievent_tcpdnsconnect(mgr, ievent); + } else { + atomic_init(&sock->active, false); +- sock->tid = isc_random_uniform(mgr->nworkers); ++ sock->tid = isc_random_uniform(mgr->nlisteners); + isc__nm_enqueue_ievent(&mgr->workers[sock->tid], + (isc__netievent_t *)ievent); + } +@@ -400,7 +400,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_sockaddr_t *iface, + #if defined(WIN32) + sock->nchildren = 1; + #else +- sock->nchildren = mgr->nworkers; ++ sock->nchildren = mgr->nlisteners; + #endif + children_size = sock->nchildren * sizeof(sock->children[0]); + sock->children = isc_mem_get(mgr->mctx, children_size); +diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c +index 1af63af..668edca 100644 +--- a/lib/isc/netmgr/udp.c ++++ b/lib/isc/netmgr/udp.c +@@ -126,7 +126,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb, + uv_os_sock_t fd = -1; + + /* +- * We are creating mgr->nworkers duplicated sockets, one ++ * We are creating mgr->nlisteners duplicated sockets, one + * socket for each worker thread. + */ + sock = isc_mem_get(mgr->mctx, sizeof(isc_nmsocket_t)); +@@ -136,7 +136,7 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb, + #if defined(WIN32) + sock->nchildren = 1; + #else +- sock->nchildren = mgr->nworkers; ++ sock->nchildren = mgr->nlisteners; + #endif + + children_size = sock->nchildren * sizeof(sock->children[0]); +@@ -795,7 +795,7 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer, + isc__nm_put_netievent_udpconnect(mgr, event); + } else { + atomic_init(&sock->active, false); +- sock->tid = isc_random_uniform(mgr->nworkers); ++ sock->tid = isc_random_uniform(mgr->nlisteners); + isc__nm_enqueue_ievent(&mgr->workers[sock->tid], + (isc__netievent_t *)event); + } +diff --git a/lib/isc/tests/netmgr_test.c b/lib/isc/tests/netmgr_test.c +index e44909e..d2c19e8 100644 +--- a/lib/isc/tests/netmgr_test.c ++++ b/lib/isc/tests/netmgr_test.c +@@ -204,8 +204,6 @@ _setup(void **state __attribute__((unused))) { + return (-1); + } + +- isc_hp_init(4 * workers); +- + signal(SIGPIPE, SIG_IGN); + + if (getenv("CI") == NULL || getenv("CI_ENABLE_ALL_TESTS") != NULL) { +-- +2.33.0 + diff --git a/backport-CVE-2023-5517.patch b/backport-CVE-2023-5517.patch new file mode 100644 index 0000000..7cb2a70 --- /dev/null +++ b/backport-CVE-2023-5517.patch @@ -0,0 +1,117 @@ +From c73262493658cb8623927ef6cc2f023501f7e809 Mon Sep 17 00:00:00 2001 +From: Mark Andrews +Date: Tue, 10 Oct 2023 10:58:18 +1100 +Subject: [PATCH] Save the correct result value to resume with + nxdomain-redirect + +The wrong result value was being saved for resumption with +nxdomain-redirect when performing the fetch. This lead to an assert +when checking that RFC 1918 reverse queries where not leaking to +the global internet. + +Conflict:NA +Reference:https://downloads.isc.org/isc/bind/9.16.48/patches/0002-CVE-2023-5517.patch + +(cherry picked from commit 9d0fa07c5e7a39db89862a4f843d2190059afb4b) +--- + lib/ns/query.c | 25 ++++++++++++------------- + 1 file changed, 12 insertions(+), 13 deletions(-) + +diff --git a/lib/ns/query.c b/lib/ns/query.c +index 62b5ea8463..55d815e6c0 100644 +--- a/lib/ns/query.c ++++ b/lib/ns/query.c +@@ -455,10 +455,10 @@ static void + query_addnxrrsetnsec(query_ctx_t *qctx); + + static isc_result_t +-query_nxdomain(query_ctx_t *qctx, bool empty_wild); ++query_nxdomain(query_ctx_t *qctx, isc_result_t result); + + static isc_result_t +-query_redirect(query_ctx_t *qctx); ++query_redirect(query_ctx_t *qctx, isc_result_t result); + + static isc_result_t + query_ncache(query_ctx_t *qctx, isc_result_t result); +@@ -7345,8 +7345,7 @@ query_usestale(query_ctx_t *qctx, isc_result_t result) { + * result from the search. + */ + static isc_result_t +-query_gotanswer(query_ctx_t *qctx, isc_result_t res) { +- isc_result_t result = res; ++query_gotanswer(query_ctx_t *qctx, isc_result_t result) { + char errmsg[256]; + + CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer"); +@@ -7416,16 +7415,16 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t res) { + return (query_nodata(qctx, DNS_R_NXRRSET)); + + case DNS_R_EMPTYWILD: +- return (query_nxdomain(qctx, true)); ++ return (query_nxdomain(qctx, DNS_R_EMPTYWILD)); + + case DNS_R_NXDOMAIN: +- return (query_nxdomain(qctx, false)); ++ return (query_nxdomain(qctx, DNS_R_NXDOMAIN)); + + case DNS_R_COVERINGNSEC: + return (query_coveringnsec(qctx)); + + case DNS_R_NCACHENXDOMAIN: +- result = query_redirect(qctx); ++ result = query_redirect(qctx, result); + if (result != ISC_R_COMPLETE) { + return (result); + } +@@ -9243,10 +9242,10 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { + * Handle NXDOMAIN and empty wildcard responses. + */ + static isc_result_t +-query_nxdomain(query_ctx_t *qctx, bool empty_wild) { ++query_nxdomain(query_ctx_t *qctx, isc_result_t result) { + dns_section_t section; + uint32_t ttl; +- isc_result_t result; ++ bool empty_wild = (result == DNS_R_EMPTYWILD); + + CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain"); + +@@ -9255,7 +9254,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { + INSIST(qctx->is_zone || REDIRECT(qctx->client)); + + if (!empty_wild) { +- result = query_redirect(qctx); ++ result = query_redirect(qctx, result); + if (result != ISC_R_COMPLETE) { + return (result); + } +@@ -9343,7 +9342,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { + * redirecting, so query processing should continue past it. + */ + static isc_result_t +-query_redirect(query_ctx_t *qctx) { ++query_redirect(query_ctx_t *qctx, isc_result_t saved_result) { + isc_result_t result; + + CCTRACE(ISC_LOG_DEBUG(3), "query_redirect"); +@@ -9384,7 +9383,7 @@ query_redirect(query_ctx_t *qctx) { + SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset); + SAVE(qctx->client->query.redirect.sigrdataset, + qctx->sigrdataset); +- qctx->client->query.redirect.result = DNS_R_NCACHENXDOMAIN; ++ qctx->client->query.redirect.result = saved_result; + dns_name_copynf(qctx->fname, + qctx->client->query.redirect.fname); + qctx->client->query.redirect.authoritative = +@@ -10005,7 +10004,7 @@ query_coveringnsec(query_ctx_t *qctx) { + * We now have the proof that we have an NXDOMAIN. Apply + * NXDOMAIN redirection if configured. + */ +- result = query_redirect(qctx); ++ result = query_redirect(qctx, DNS_R_COVERINGNSEC); + if (result != ISC_R_COMPLETE) { + redirected = true; + goto cleanup; +-- +GitLab diff --git a/backport-CVE-2023-5679.patch b/backport-CVE-2023-5679.patch new file mode 100644 index 0000000..e3c67e0 --- /dev/null +++ b/backport-CVE-2023-5679.patch @@ -0,0 +1,38 @@ +From 7db2796507127b40e2f091dafb842c6a7e86b9a8 Mon Sep 17 00:00:00 2001 +From: Mark Andrews +Date: Thu, 12 Oct 2023 12:01:46 +1100 +Subject: [PATCH] Restore dns64 state during serve-stale processing + +If we are in the process of looking for the A records as part of +dns64 processing and the server-stale timeout triggers, redo the +dns64 changes that had been made to the orignal qctx. + +Conflict:NA +Reference:https://downloads.isc.org/isc/bind/9.16.48/patches/0003-CVE-2023-5679.patch + +(cherry picked from commit 1fcc483df13e049b96f620e515f0d4d45f3680b7) +--- + lib/ns/query.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/lib/ns/query.c b/lib/ns/query.c +index 55d815e6c0..1290c308af 100644 +--- a/lib/ns/query.c ++++ b/lib/ns/query.c +@@ -6095,6 +6095,13 @@ query_lookup_stale(ns_client_t *client) { + query_ctx_t qctx; + + qctx_init(client, NULL, client->query.qtype, &qctx); ++ if (DNS64(client)) { ++ qctx.qtype = qctx.type = dns_rdatatype_a; ++ qctx.dns64 = true; ++ } ++ if (DNS64EXCLUDE(client)) { ++ qctx.dns64_exclude = true; ++ } + dns_db_attach(client->view->cachedb, &qctx.db); + client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK; + client->query.dboptions |= DNS_DBFIND_STALETIMEOUT; +-- +GitLab + diff --git a/backport-CVE-2023-6516.patch b/backport-CVE-2023-6516.patch new file mode 100644 index 0000000..748dfb4 --- /dev/null +++ b/backport-CVE-2023-6516.patch @@ -0,0 +1,294 @@ +From c3377cbfaa44dcb033f5abfb2db031612c8f47d1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= +Date: Thu, 4 Jan 2024 13:39:27 +0100 +Subject: [PATCH] Limit isc_task_send() overhead for tree pruning + +Instead of issuing a separate isc_task_send() call for every RBTDB node +that triggers tree pruning, maintain a list of nodes from which tree +pruning can be started from and only issue an isc_task_send() call if +pruning has not yet been triggered by another RBTDB node. + +The extra queuing overhead eliminated by this change could be remotely +exploited to cause excessive memory use. + +As this change modifies struct dns_rbtnode by adding a new 'prunelink' +member to it, bump MAPAPI to prevent any attempts of loading map-format +zone files created using older BIND 9 versions. + +Conflict:NA +Reference:https://downloads.isc.org/isc/bind/9.16.48/patches/0004-CVE-2023-6516.patch + +(cherry picked from commit 24381cc36d8528f5a4046fb2614451aeac4cdfc1) +--- + lib/dns/include/dns/rbt.h | 6 ++ + lib/dns/mapapi | 2 +- + lib/dns/rbt.c | 1 + + lib/dns/rbtdb.c | 150 +++++++++++++++++++++++++------------- + 4 files changed, 108 insertions(+), 51 deletions(-) + +diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h +index b67e602..0e48e1d 100644 +--- a/lib/dns/include/dns/rbt.h ++++ b/lib/dns/include/dns/rbt.h +@@ -138,6 +138,12 @@ struct dns_rbtnode { + */ + ISC_LINK(dns_rbtnode_t) deadlink; + ++ /*% ++ * This linked list is used to store nodes from which tree pruning can ++ * be started. ++ */ ++ ISC_LINK(dns_rbtnode_t) prunelink; ++ + /*@{*/ + /*! + * These values are used in the RBT DB implementation. The appropriate +diff --git a/lib/dns/mapapi b/lib/dns/mapapi +index 1b502d3..a46e190 100644 +--- a/lib/dns/mapapi ++++ b/lib/dns/mapapi +@@ -13,4 +13,4 @@ + # Whenever releasing a new major release of BIND9, set this value + # back to 1.0 when releasing the first alpha. Map files are *never* + # compatible across major releases. +-MAPAPI=3.0 ++MAPAPI=4.0 +diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c +index 3fa2999..d453622 100644 +--- a/lib/dns/rbt.c ++++ b/lib/dns/rbt.c +@@ -2292,6 +2292,7 @@ create_node(isc_mem_t *mctx, const dns_name_t *name, dns_rbtnode_t **nodep) { + HASHVAL(node) = 0; + + ISC_LINK_INIT(node, deadlink); ++ ISC_LINK_INIT(node, prunelink); + + LOCKNUM(node) = 0; + WILD(node) = 0; +diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c +index c25023c..ab4caae 100644 +--- a/lib/dns/rbtdb.c ++++ b/lib/dns/rbtdb.c +@@ -515,6 +515,10 @@ struct dns_rbtdb { + */ + rbtnodelist_t *deadnodes; + ++ /* List of nodes from which recursive tree pruning can be started from. ++ * Locked by tree_lock. */ ++ rbtnodelist_t prunenodes; ++ + /* + * Heaps. These are used for TTL based expiry in a cache, + * or for zone resigning in a zone DB. hmctx is the memory +@@ -1060,6 +1064,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { + unsigned int i; + isc_result_t result; + char buf[DNS_NAME_FORMATSIZE]; ++ dns_rbtnode_t *node = NULL; + dns_rbt_t **treep; + isc_time_t start; + +@@ -1085,8 +1090,6 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { + * the overhead of unlinking all nodes here should be negligible. + */ + for (i = 0; i < rbtdb->node_lock_count; i++) { +- dns_rbtnode_t *node; +- + node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); + while (node != NULL) { + ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink); +@@ -1094,6 +1097,12 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { + } + } + ++ node = ISC_LIST_HEAD(rbtdb->prunenodes); ++ while (node != NULL) { ++ ISC_LIST_UNLINK(rbtdb->prunenodes, node, prunelink); ++ node = ISC_LIST_HEAD(rbtdb->prunenodes); ++ } ++ + if (event == NULL) { + rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0; + } +@@ -1926,19 +1935,33 @@ is_leaf(dns_rbtnode_t *node) { + node->left == NULL && node->right == NULL); + } + ++/*% ++ * The tree lock must be held when this function is called as it reads and ++ * updates rbtdb->prunenodes. ++ */ + static inline void + send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + isc_rwlocktype_t locktype) { +- isc_event_t *ev; +- dns_db_t *db; ++ bool pruning_queued = (ISC_LIST_HEAD(rbtdb->prunenodes) != NULL); ++ ++ INSIST(locktype == isc_rwlocktype_write); + +- ev = isc_event_allocate(rbtdb->common.mctx, NULL, DNS_EVENT_RBTPRUNE, +- prune_tree, node, sizeof(isc_event_t)); + new_reference(rbtdb, node, locktype); +- db = NULL; +- attach((dns_db_t *)rbtdb, &db); +- ev->ev_sender = db; +- isc_task_send(rbtdb->task, &ev); ++ INSIST(!ISC_LINK_LINKED(node, prunelink)); ++ ISC_LIST_APPEND(rbtdb->prunenodes, node, prunelink); ++ ++ if (!pruning_queued) { ++ isc_event_t *ev = NULL; ++ dns_db_t *db = NULL; ++ ++ attach((dns_db_t *)rbtdb, &db); ++ ++ ev = isc_event_allocate(rbtdb->common.mctx, NULL, ++ DNS_EVENT_RBTPRUNE, prune_tree, db, ++ sizeof(isc_event_t)); ++ isc_task_send(rbtdb->task, &ev); ++ } ++ + } + + /*% +@@ -2212,17 +2235,26 @@ restore_locks: + } + + /* +- * Prune the tree by recursively cleaning-up single leaves. In the worst +- * case, the number of iteration is the number of tree levels, which is at +- * most the maximum number of domain name labels, i.e, 127. In practice, this +- * should be much smaller (only a few times), and even the worst case would be +- * acceptable for a single event. ++ * Prune the tree by recursively cleaning up single leaves. Go through all ++ * nodes stored in the rbtdb->prunenodes list; for each of them, in the worst ++ * case, it will be necessary to traverse a number of tree levels equal to the ++ * maximum legal number of domain name labels (127); in practice, the number of ++ * tree levels to traverse will virtually always be much smaller (a few levels ++ * at most). While holding the tree lock throughout this entire operation is ++ * less than ideal, so is splitting the latter up by queueing a separate ++ * prune_tree() run for each node to start pruning from (as queueing requires ++ * allocating memory and can therefore potentially be exploited to exhaust ++ * available memory). Also note that actually freeing up the memory used by ++ * RBTDB nodes (which is what this function does) is essential to keeping cache ++ * memory use in check, so since the tree lock needs to be acquired anyway, ++ * freeing as many nodes as possible before the tree lock gets released is ++ * prudent. + */ + static void + prune_tree(isc_task_t *task, isc_event_t *event) { +- dns_rbtdb_t *rbtdb = event->ev_sender; +- dns_rbtnode_t *node = event->ev_arg; +- dns_rbtnode_t *parent; ++ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)event->ev_arg; ++ dns_rbtnode_t *node = NULL; ++ dns_rbtnode_t *parent = NULL; + unsigned int locknum; + + UNUSED(task); +@@ -2230,44 +2262,60 @@ prune_tree(isc_task_t *task, isc_event_t *event) { + isc_event_free(&event); + + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); +- locknum = node->locknum; +- NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); +- do { +- parent = node->parent; +- decrement_reference(rbtdb, node, 0, isc_rwlocktype_write, +- isc_rwlocktype_write, true); + +- if (parent != NULL && parent->down == NULL) { +- /* +- * node was the only down child of the parent and has +- * just been removed. We'll then need to examine the +- * parent. Keep the lock if possible; otherwise, +- * release the old lock and acquire one for the parent. +- */ +- if (parent->locknum != locknum) { +- NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, +- isc_rwlocktype_write); +- locknum = parent->locknum; +- NODE_LOCK(&rbtdb->node_locks[locknum].lock, +- isc_rwlocktype_write); ++ while ((node = ISC_LIST_HEAD(rbtdb->prunenodes)) != NULL) { ++ locknum = node->locknum; ++ NODE_LOCK(&rbtdb->node_locks[locknum].lock, ++ isc_rwlocktype_write); ++ do { ++ if (ISC_LINK_LINKED(node, prunelink)) { ++ ISC_LIST_UNLINK(rbtdb->prunenodes, node, ++ prunelink); + } + +- /* +- * We need to gain a reference to the node before +- * decrementing it in the next iteration. +- */ +- if (ISC_LINK_LINKED(parent, deadlink)) { +- ISC_LIST_UNLINK(rbtdb->deadnodes[locknum], ++ parent = node->parent; ++ decrement_reference(rbtdb, node, 0, ++ isc_rwlocktype_write, ++ isc_rwlocktype_write, true); ++ ++ if (parent != NULL && parent->down == NULL) { ++ /* ++ * node was the only down child of the parent ++ * and has just been removed. We'll then need ++ * to examine the parent. Keep the lock if ++ * possible; otherwise, release the old lock and ++ * acquire one for the parent. ++ */ ++ if (parent->locknum != locknum) { ++ NODE_UNLOCK( ++ &rbtdb->node_locks[locknum].lock, ++ isc_rwlocktype_write); ++ locknum = parent->locknum; ++ NODE_LOCK( ++ &rbtdb->node_locks[locknum].lock, ++ isc_rwlocktype_write); ++ } ++ ++ /* ++ * We need to gain a reference to the node ++ * before decrementing it in the next iteration. ++ */ ++ if (ISC_LINK_LINKED(parent, deadlink)) { ++ ISC_LIST_UNLINK( ++ rbtdb->deadnodes[locknum], + parent, deadlink); ++ } ++ new_reference(rbtdb, parent, ++ isc_rwlocktype_write); ++ } else { ++ parent = NULL; + } +- new_reference(rbtdb, parent, isc_rwlocktype_write); +- } else { +- parent = NULL; +- } + +- node = parent; +- } while (node != NULL); +- NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); ++ node = parent; ++ } while (node != NULL); ++ NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, ++ isc_rwlocktype_write); ++ } + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + + detach((dns_db_t **)&rbtdb); +@@ -8718,6 +8766,8 @@ dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, + ISC_LIST_INIT(rbtdb->deadnodes[i]); + } + ++ ISC_LIST_INIT(rbtdb->prunenodes); ++ + rbtdb->active = rbtdb->node_lock_count; + + for (i = 0; i < (int)(rbtdb->node_lock_count); i++) { +-- +2.33.0 + diff --git a/backport-Disable-the-internale-memory-allocator-by-default.patch b/backport-Disable-the-internal-memory-allocator-by-default.patch similarity index 77% rename from backport-Disable-the-internale-memory-allocator-by-default.patch rename to backport-Disable-the-internal-memory-allocator-by-default.patch index e45b21a..7f979cb 100644 --- a/backport-Disable-the-internale-memory-allocator-by-default.patch +++ b/backport-Disable-the-internal-memory-allocator-by-default.patch @@ -1,10 +1,10 @@ From 1f7d2d53f0e5b86e22e1dd116868bb69eeacb1a0 Mon Sep 17 00:00:00 2001 -From: Ondrej Sur -Date: Wed, 15 Dec 2021 08:25:29 PM GMT+0800 -Subject: [PATCH] Disable the internale memory allocator by default +From: Ondřej Sur +Date: Wed, 15 Dec 2021 08:25:42 PM GMT+0800 +Subject: [PATCH] Disable the internal memory allocator by default Conflict:NA -Reference:https://githun.com/isc-projects/bind9/commit/1f7d2d53f0e5b86e22e1dd116868bb69eeacb1a0 +Reference:https://github.com/isc-projects/bind9/commit/1f7d2d53f0e5b86e22e1dd116868bb69eeacb1a0 --- bin/named/main.c | 1 + @@ -12,14 +12,14 @@ Reference:https://githun.com/isc-projects/bind9/commit/1f7d2d53f0e5b86e22e1dd116 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/named/main.c b/bin/named/main.c -index f62f82c..b3d2498 100644 +index f62f82c..c7c35ce 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -456,6 +456,7 @@ static struct flag_def { { "mctx", ISC_MEM_DEBUGCTX, false }, { NULL, 0, false } }, mem_context_flags[] = { { "external", ISC_MEMFLAG_INTERNAL, true }, -+ { "internal", ISC_MEMFLAG_INTERNAL, false }, ++ { "internal", ISC_MEMFLAG_INTERNAL, false }, { "fill", ISC_MEMFLAG_FILL, false }, { "nofill", ISC_MEMFLAG_FILL, true }, { NULL, 0, false } }; @@ -37,5 +37,5 @@ index 58e1d0e..b9f58fa 100644 /* -- -2.23.0 +2.33.0 diff --git a/backport-Make-isc_ht_init-and-isc_ht_iter_create-return-void.patch b/backport-Make-isc_ht_init-and-isc_ht_iter_create-return-void.patch new file mode 100644 index 0000000..d340c05 --- /dev/null +++ b/backport-Make-isc_ht_init-and-isc_ht_iter_create-return-void.patch @@ -0,0 +1,408 @@ +From ba89da052a025928823055614e3f43fe8f8e3ef8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= +Date: Tue, 8 Mar 2022 11:22:55 +0100 +Subject: [PATCH] Make isc_ht_init() and isc_ht_iter_create() return void + +Previously, the function(s) in the commit subject could fail for various +reasons - mostly allocation failures, or other functions returning +different return code than ISC_R_SUCCESS. Now, the aforementioned +function(s) cannot ever fail and they would always return ISC_R_SUCCESS. + +Change the function(s) to return void and remove the extra checks in +the code that uses them. + +Conflict:NA +Reference:https://gitlab.isc.org/isc-projects/bind9/-/commit/ba89da052a025928823055614e3f43fe8f8e3ef8.patch + +(cherry picked from commit 8fa27365ec8ea47b498ea64a9b72553c0b662b6b) +--- + bin/plugins/filter-aaaa.c | 4 +- + lib/dns/catz.c | 82 ++++++++++----------------------------- + lib/dns/rpz.c | 29 ++------------ + lib/isc/ht.c | 7 +--- + lib/isc/include/isc/ht.h | 13 +++---- + lib/isc/tests/ht_test.c | 9 ++--- + 6 files changed, 35 insertions(+), 109 deletions(-) + +diff --git a/bin/plugins/filter-aaaa.c b/bin/plugins/filter-aaaa.c +index 1db3ca2..c390b45 100644 +--- a/bin/plugins/filter-aaaa.c ++++ b/bin/plugins/filter-aaaa.c +@@ -337,7 +337,7 @@ plugin_register(const char *parameters, const void *cfg, const char *cfg_file, + unsigned long cfg_line, isc_mem_t *mctx, isc_log_t *lctx, + void *actx, ns_hooktable_t *hooktable, void **instp) { + filter_instance_t *inst = NULL; +- isc_result_t result; ++ isc_result_t result = ISC_R_SUCCESS; + + isc_log_write(lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, + ISC_LOG_INFO, +@@ -355,7 +355,7 @@ plugin_register(const char *parameters, const void *cfg, const char *cfg_file, + } + + isc_mempool_create(mctx, sizeof(filter_data_t), &inst->datapool); +- CHECK(isc_ht_init(&inst->ht, mctx, 16)); ++ isc_ht_init(&inst->ht, mctx, 16); + isc_mutex_init(&inst->hlock); + + /* +diff --git a/lib/dns/catz.c b/lib/dns/catz.c +index 77b7a24..fbe13f4 100644 +--- a/lib/dns/catz.c ++++ b/lib/dns/catz.c +@@ -418,39 +418,21 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) { + + dns_name_format(&target->name, czname, DNS_NAME_FORMATSIZE); + +- result = isc_ht_init(&toadd, target->catzs->mctx, 16); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ isc_ht_init(&toadd, target->catzs->mctx, 16); + +- result = isc_ht_init(&tomod, target->catzs->mctx, 16); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ isc_ht_init(&tomod, target->catzs->mctx, 16); + +- result = isc_ht_iter_create(newzone->entries, &iter1); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ isc_ht_iter_create(newzone->entries, &iter1); + +- result = isc_ht_iter_create(target->entries, &iter2); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ isc_ht_iter_create(target->entries, &iter2); + + /* + * We can create those iterators now, even though toadd and tomod are + * empty + */ +- result = isc_ht_iter_create(toadd, &iteradd); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ isc_ht_iter_create(toadd, &iteradd); + +- result = isc_ht_iter_create(tomod, &itermod); +- if (result != ISC_R_SUCCESS) { +- goto cleanup; +- } ++ isc_ht_iter_create(tomod, &itermod); + + /* + * First - walk the new zone and find all nodes that are not in the +@@ -598,25 +580,11 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) { + + result = ISC_R_SUCCESS; + +-cleanup: +- if (iter1 != NULL) { +- isc_ht_iter_destroy(&iter1); +- } +- if (iter2 != NULL) { +- isc_ht_iter_destroy(&iter2); +- } +- if (iteradd != NULL) { +- isc_ht_iter_destroy(&iteradd); +- } +- if (itermod != NULL) { +- isc_ht_iter_destroy(&itermod); +- } +- if (toadd != NULL) { +- isc_ht_destroy(&toadd); +- } +- if (tomod != NULL) { +- isc_ht_destroy(&tomod); +- } ++ isc_ht_iter_destroy(&iteradd); ++ isc_ht_iter_destroy(&itermod); ++ isc_ht_destroy(&toadd); ++ isc_ht_destroy(&tomod); ++ + return (result); + } + +@@ -637,10 +605,7 @@ dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm, + + isc_refcount_init(&new_zones->refs, 1); + +- result = isc_ht_init(&new_zones->zones, mctx, 4); +- if (result != ISC_R_SUCCESS) { +- goto cleanup_refcount; +- } ++ isc_ht_init(&new_zones->zones, mctx, 4); + + isc_mem_attach(mctx, &new_zones->mctx); + new_zones->zmm = zmm; +@@ -658,7 +623,6 @@ dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm, + + cleanup_ht: + isc_ht_destroy(&new_zones->zones); +-cleanup_refcount: + isc_refcount_destroy(&new_zones->refs); + isc_mutex_destroy(&new_zones->lock); + isc_mem_putanddetach(&new_zones->mctx, new_zones, sizeof(*new_zones)); +@@ -693,10 +657,7 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep, + dns_name_init(&new_zone->name, NULL); + dns_name_dup(name, catzs->mctx, &new_zone->name); + +- result = isc_ht_init(&new_zone->entries, catzs->mctx, 4); +- if (result != ISC_R_SUCCESS) { +- goto cleanup_name; +- } ++ isc_ht_init(&new_zone->entries, catzs->mctx, 4); + + new_zone->updatetimer = NULL; + result = isc_timer_create(catzs->timermgr, isc_timertype_inactive, NULL, +@@ -726,7 +687,6 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep, + + cleanup_ht: + isc_ht_destroy(&new_zone->entries); +-cleanup_name: + dns_name_free(&new_zone->name, catzs->mctx); + isc_mem_put(catzs->mctx, new_zone, sizeof(*new_zone)); + +@@ -827,8 +787,7 @@ dns_catz_zone_detach(dns_catz_zone_t **zonep) { + if (zone->entries != NULL) { + isc_ht_iter_t *iter = NULL; + isc_result_t result; +- result = isc_ht_iter_create(zone->entries, &iter); +- INSIST(result == ISC_R_SUCCESS); ++ isc_ht_iter_create(zone->entries, &iter); + for (result = isc_ht_iter_first(iter); + result == ISC_R_SUCCESS; + result = isc_ht_iter_delcurrent_next(iter)) +@@ -884,8 +843,7 @@ dns_catz_catzs_detach(dns_catz_zones_t **catzsp) { + if (catzs->zones != NULL) { + isc_ht_iter_t *iter = NULL; + isc_result_t result; +- result = isc_ht_iter_create(catzs->zones, &iter); +- INSIST(result == ISC_R_SUCCESS); ++ isc_ht_iter_create(catzs->zones, &iter); + for (result = isc_ht_iter_first(iter); + result == ISC_R_SUCCESS;) { + dns_catz_zone_t *zone = NULL; +@@ -2060,8 +2018,7 @@ dns_catz_prereconfig(dns_catz_zones_t *catzs) { + + REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); + +- result = isc_ht_iter_create(catzs->zones, &iter); +- INSIST(result == ISC_R_SUCCESS); ++ isc_ht_iter_create(catzs->zones, &iter); + for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; + result = isc_ht_iter_next(iter)) + { +@@ -2082,8 +2039,7 @@ dns_catz_postreconfig(dns_catz_zones_t *catzs) { + REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); + + LOCK(&catzs->lock); +- result = isc_ht_iter_create(catzs->zones, &iter); +- INSIST(result == ISC_R_SUCCESS); ++ isc_ht_iter_create(catzs->zones, &iter); + for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;) { + dns_catz_zone_t *zone = NULL; + +@@ -2122,5 +2078,7 @@ dns_catz_postreconfig(dns_catz_zones_t *catzs) { + isc_result_t + dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp) { + REQUIRE(DNS_CATZ_ZONE_VALID(catz)); +- return (isc_ht_iter_create(catz->entries, itp)); ++ isc_ht_iter_create(catz->entries, itp); ++ ++ return (ISC_R_SUCCESS); + } +diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c +index 1bdaac9..13cfc85 100644 +--- a/lib/dns/rpz.c ++++ b/lib/dns/rpz.c +@@ -1541,10 +1541,7 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { + * simplifies update_from_db + */ + +- result = isc_ht_init(&zone->nodes, rpzs->mctx, 1); +- if (result != ISC_R_SUCCESS) { +- goto cleanup_ht; +- } ++ isc_ht_init(&zone->nodes, rpzs->mctx, 1); + + dns_name_init(&zone->origin, NULL); + dns_name_init(&zone->client_ip, NULL); +@@ -1578,9 +1575,6 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { + + return (ISC_R_SUCCESS); + +-cleanup_ht: +- isc_timer_detach(&zone->updatetimer); +- + cleanup_timer: + isc_refcount_decrementz(&zone->refs); + isc_refcount_destroy(&zone->refs); +@@ -1724,14 +1718,7 @@ setup_update(dns_rpz_zone_t *rpz) { + ISC_LOG_DEBUG(1), "rpz: %s: using hashtable size %d", + domain, hashsize); + +- result = isc_ht_init(&rpz->newnodes, rpz->rpzs->mctx, hashsize); +- if (result != ISC_R_SUCCESS) { +- isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, +- DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, +- "rpz: %s: failed to initialize hashtable - %s", +- domain, isc_result_totext(result)); +- goto cleanup; +- } ++ isc_ht_init(&rpz->newnodes, rpz->rpzs->mctx, hashsize); + + result = dns_db_createiterator(rpz->updb, DNS_DB_NONSEC3, &rpz->updbit); + if (result != ISC_R_SUCCESS) { +@@ -1838,17 +1825,7 @@ cleanup_quantum(isc_task_t *task, isc_event_t *event) { + * Iterate over old ht with existing nodes deleted to + * delete deleted nodes from RPZ + */ +- result = isc_ht_iter_create(rpz->nodes, &iter); +- if (result != ISC_R_SUCCESS) { +- dns_name_format(&rpz->origin, domain, +- DNS_NAME_FORMATSIZE); +- isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, +- DNS_LOGMODULE_MASTER, ISC_LOG_ERROR, +- "rpz: %s: failed to create HT " +- "iterator - %s", +- domain, isc_result_totext(result)); +- goto cleanup; +- } ++ isc_ht_iter_create(rpz->nodes, &iter); + } + + name = dns_fixedname_initname(&fname); +diff --git a/lib/isc/ht.c b/lib/isc/ht.c +index 82f8ac8..88e8578 100644 +--- a/lib/isc/ht.c ++++ b/lib/isc/ht.c +@@ -47,7 +47,7 @@ struct isc_ht_iter { + isc_ht_node_t *cur; + }; + +-isc_result_t ++void + isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { + isc_ht_t *ht = NULL; + size_t i; +@@ -74,7 +74,6 @@ isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits) { + ht->magic = ISC_HT_MAGIC; + + *htp = ht; +- return (ISC_R_SUCCESS); + } + + void +@@ -199,7 +198,7 @@ isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize) { + return (ISC_R_NOTFOUND); + } + +-isc_result_t ++void + isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { + isc_ht_iter_t *it; + +@@ -213,8 +212,6 @@ isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) { + it->cur = NULL; + + *itp = it; +- +- return (ISC_R_SUCCESS); + } + + void +diff --git a/lib/isc/include/isc/ht.h b/lib/isc/include/isc/ht.h +index 9d5ab82..280ee7e 100644 +--- a/lib/isc/include/isc/ht.h ++++ b/lib/isc/include/isc/ht.h +@@ -31,11 +31,8 @@ typedef struct isc_ht_iter isc_ht_iter_t; + *\li 'mctx' is a valid memory context. + *\li 'bits' >=1 and 'bits' <=32 + * +- * Returns: +- *\li #ISC_R_NOMEMORY -- not enough memory to create pool +- *\li #ISC_R_SUCCESS -- all is well. + */ +-isc_result_t ++void + isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, uint8_t bits); + + /*% +@@ -100,7 +97,7 @@ isc_ht_delete(isc_ht_t *ht, const unsigned char *key, uint32_t keysize); + *\li 'ht' is a valid hashtable + *\li 'itp' is non NULL and '*itp' is NULL. + */ +-isc_result_t ++void + isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp); + + /*% +@@ -119,7 +116,7 @@ isc_ht_iter_destroy(isc_ht_iter_t **itp); + *\li 'it' is non NULL. + * + * Returns: +- * \li #ISC_R_SUCCESS -- success ++ * \li #ISC_R_SUCCESS -- success + * \li #ISC_R_NOMORE -- no data in the hashtable + */ + isc_result_t +@@ -132,7 +129,7 @@ isc_ht_iter_first(isc_ht_iter_t *it); + *\li 'it' is non NULL. + * + * Returns: +- * \li #ISC_R_SUCCESS -- success ++ * \li #ISC_R_SUCCESS -- success + * \li #ISC_R_NOMORE -- end of hashtable reached + */ + isc_result_t +@@ -145,7 +142,7 @@ isc_ht_iter_next(isc_ht_iter_t *it); + *\li 'it' is non NULL. + * + * Returns: +- * \li #ISC_R_SUCCESS -- success ++ * \li #ISC_R_SUCCESS -- success + * \li #ISC_R_NOMORE -- end of hashtable reached + */ + isc_result_t +diff --git a/lib/isc/tests/ht_test.c b/lib/isc/tests/ht_test.c +index 6a8e319..61b8c3d 100644 +--- a/lib/isc/tests/ht_test.c ++++ b/lib/isc/tests/ht_test.c +@@ -59,8 +59,7 @@ test_ht_full(int bits, uintptr_t count) { + isc_result_t result; + uintptr_t i; + +- result = isc_ht_init(&ht, test_mctx, bits); +- assert_int_equal(result, ISC_R_SUCCESS); ++ isc_ht_init(&ht, test_mctx, bits); + assert_non_null(ht); + + for (i = 1; i < count; i++) { +@@ -205,8 +204,7 @@ test_ht_iterator() { + unsigned char key[16]; + size_t tksize; + +- result = isc_ht_init(&ht, test_mctx, 16); +- assert_int_equal(result, ISC_R_SUCCESS); ++ isc_ht_init(&ht, test_mctx, 16); + assert_non_null(ht); + for (i = 1; i <= count; i++) { + /* +@@ -220,8 +218,7 @@ test_ht_iterator() { + } + + walked = 0; +- result = isc_ht_iter_create(ht, &iter); +- assert_int_equal(result, ISC_R_SUCCESS); ++ isc_ht_iter_create(ht, &iter); + + for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS; + result = isc_ht_iter_next(iter)) +-- +2.33.0 + diff --git a/backport-Replace-netievent-lock-free-queue-with-simple-locked.patch b/backport-Replace-netievent-lock-free-queue-with-simple-locked.patch new file mode 100644 index 0000000..66b0abb --- /dev/null +++ b/backport-Replace-netievent-lock-free-queue-with-simple-locked.patch @@ -0,0 +1,1353 @@ +From 32a3970b13643df0102e2e5312f345a1b3833a67 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= +Date: Tue, 22 Feb 2022 23:40:39 +0100 +Subject: [PATCH] Replace netievent lock-free queue with simple locked queue + +The current implementation of isc_queue uses Michael-Scott lock-free +queue that in turn uses hazard pointers. It was discovered that the way +we use the isc_queue, such complicated mechanism isn't really needed, +because most of the time, we either execute the work directly when on +nmthread (in case of UDP) or schedule the work from the matching +nmthreads. + +Replace the current implementation of the isc_queue with a simple locked +ISC_LIST. There's a slight improvement - since copying the whole list +is very lightweight - we move the queue into a new list before we start +the processing and locking just for moving the queue and not for every +single item on the list. + +NOTE: There's a room for future improvements - since we don't guarantee +the order in which the netievents are processed, we could have two lists +- one unlocked that would be used when scheduling the work from the +matching thread and one locked that would be used from non-matching +thread. + +(cherry picked from commit 6bd025942c4aeef42ef06f380a70c70acf490b1d) + +Conflict:The pre-reconstruction patch 75f9dd8e is not integrated. Therefore, netmgr.c needs to be adapted +Reference:https://gitlab.isc.org/isc-projects/bind9/-/commit/32a3970b13643df0102e2e5312f345a1b3833a67 + +--- + bin/named/main.c | 1 - + lib/isc/Makefile.in | 8 +- + lib/isc/hp.c | 205 --------------------- + lib/isc/include/isc/Makefile.in | 4 +- + lib/isc/include/isc/hp.h | 138 -------------- + lib/isc/include/isc/list.h | 17 +- + lib/isc/include/isc/queue.h | 54 ------ + lib/isc/include/isc/types.h | 8 +- + lib/isc/managers.c | 7 - + lib/isc/netmgr/netmgr-int.h | 33 ++-- + lib/isc/netmgr/netmgr.c | 227 ++++++++++------------- + lib/isc/queue.c | 232 ------------------------ + lib/isc/task.c | 2 +- + lib/isc/tests/netmgr_test.c | 1 - + lib/isc/win32/libisc.def.in | 20 -- + 15 files changed, 137 insertions(+), 821 deletions(-) + delete mode 100644 lib/isc/hp.c + delete mode 100644 lib/isc/include/isc/hp.h + delete mode 100644 lib/isc/include/isc/queue.h + delete mode 100644 lib/isc/queue.c + +diff --git a/bin/named/main.c b/bin/named/main.c +index c7c35ce..0bd3397 100644 +--- a/bin/named/main.c ++++ b/bin/named/main.c +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in +index 2cf73e0..1c711bd 100644 +--- a/lib/isc/Makefile.in ++++ b/lib/isc/Makefile.in +@@ -51,14 +51,14 @@ OBJS = pk11.@O@ pk11_result.@O@ \ + bind9.@O@ buffer.@O@ bufferlist.@O@ \ + commandline.@O@ counter.@O@ crc64.@O@ error.@O@ entropy.@O@ \ + event.@O@ hash.@O@ ht.@O@ heap.@O@ hex.@O@ \ +- hmac.@O@ hp.@O@ httpd.@O@ iterated_hash.@O@ \ ++ hmac.@O@ httpd.@O@ iterated_hash.@O@ \ + lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \ + managers.@O@ md.@O@ mem.@O@ mutexblock.@O@ \ + netmgr/netmgr.@O@ netmgr/tcp.@O@ netmgr/udp.@O@ \ + netmgr/tcpdns.@O@ \ + netmgr/uverr2result.@O@ netmgr/uv-compat.@O@ \ + netaddr.@O@ netscope.@O@ nonce.@O@ openssl_shim.@O@ pool.@O@ \ +- parseint.@O@ portset.@O@ queue.@O@ quota.@O@ \ ++ parseint.@O@ portset.@O@ quota.@O@ \ + radix.@O@ random.@O@ ratelimiter.@O@ \ + region.@O@ regex.@O@ result.@O@ rwlock.@O@ \ + safe.@O@ serial.@O@ siphash.@O@ sockaddr.@O@ stats.@O@ \ +@@ -74,11 +74,11 @@ SRCS = pk11.c pk11_result.c \ + backtrace.c base32.c base64.c bind9.c \ + buffer.c bufferlist.c commandline.c counter.c crc64.c \ + entropy.c error.c event.c hash.c ht.c heap.c \ +- hex.c hmac.c hp.c httpd.c iterated_hash.c \ ++ hex.c hmac.c httpd.c iterated_hash.c \ + lex.c lfsr.c lib.c log.c \ + managers.c md.c mem.c mutexblock.c \ + netaddr.c netscope.c nonce.c openssl_shim.c pool.c \ +- parseint.c portset.c queue.c quota.c radix.c random.c \ ++ parseint.c portset.c quota.c radix.c random.c \ + ratelimiter.c region.c regex.c result.c rwlock.c \ + safe.c serial.c siphash.c sockaddr.c stats.c string.c \ + symtab.c task.c taskpool.c timer.c tls.c \ +diff --git a/lib/isc/hp.c b/lib/isc/hp.c +deleted file mode 100644 +index 92d160b..0000000 +--- a/lib/isc/hp.c ++++ /dev/null +@@ -1,205 +0,0 @@ +-/* +- * Copyright (C) Internet Systems Consortium, Inc. ("ISC") +- * +- * 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. +- */ +- +-/* +- * Hazard Pointer implementation. +- * +- * This work is based on C++ code available from: +- * https://github.com/pramalhe/ConcurrencyFreaks/ +- * +- * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions are met: +- * +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * * Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * * Neither the name of Concurrency Freaks nor the +- * names of its contributors may be used to endorse or promote products +- * derived from this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +- * THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define HP_MAX_THREADS 128 +-static int isc__hp_max_threads = HP_MAX_THREADS; +-#define HP_MAX_HPS 4 /* This is named 'K' in the HP paper */ +-#define CLPAD (128 / sizeof(uintptr_t)) +-#define HP_THRESHOLD_R 0 /* This is named 'R' in the HP paper */ +- +-/* Maximum number of retired objects per thread */ +-static int isc__hp_max_retired = HP_MAX_THREADS * HP_MAX_HPS; +- +-typedef struct retirelist { +- int size; +- uintptr_t *list; +-} retirelist_t; +- +-struct isc_hp { +- int max_hps; +- isc_mem_t *mctx; +- atomic_uintptr_t **hp; +- retirelist_t **rl; +- isc_hp_deletefunc_t *deletefunc; +-}; +- +-static inline int +-tid(void) { +- return (isc_tid_v); +-} +- +-void +-isc_hp_init(int max_threads) { +- isc__hp_max_threads = max_threads; +- isc__hp_max_retired = max_threads * HP_MAX_HPS; +-} +- +-isc_hp_t * +-isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc) { +- isc_hp_t *hp = isc_mem_get(mctx, sizeof(*hp)); +- +- if (max_hps == 0) { +- max_hps = HP_MAX_HPS; +- } +- +- *hp = (isc_hp_t){ .max_hps = max_hps, .deletefunc = deletefunc }; +- +- isc_mem_attach(mctx, &hp->mctx); +- +- hp->hp = isc_mem_get(mctx, isc__hp_max_threads * sizeof(hp->hp[0])); +- hp->rl = isc_mem_get(mctx, isc__hp_max_threads * sizeof(hp->rl[0])); +- +- for (int i = 0; i < isc__hp_max_threads; i++) { +- hp->hp[i] = isc_mem_get(mctx, CLPAD * 2 * sizeof(hp->hp[i][0])); +- hp->rl[i] = isc_mem_get(mctx, sizeof(*hp->rl[0])); +- *hp->rl[i] = (retirelist_t){ .size = 0 }; +- +- for (int j = 0; j < hp->max_hps; j++) { +- atomic_init(&hp->hp[i][j], 0); +- } +- hp->rl[i]->list = isc_mem_get( +- hp->mctx, isc__hp_max_retired * sizeof(uintptr_t)); +- } +- +- return (hp); +-} +- +-void +-isc_hp_destroy(isc_hp_t *hp) { +- for (int i = 0; i < isc__hp_max_threads; i++) { +- isc_mem_put(hp->mctx, hp->hp[i], +- CLPAD * 2 * sizeof(hp->hp[i][0])); +- +- for (int j = 0; j < hp->rl[i]->size; j++) { +- void *data = (void *)hp->rl[i]->list[j]; +- hp->deletefunc(data); +- } +- isc_mem_put(hp->mctx, hp->rl[i]->list, +- isc__hp_max_retired * sizeof(uintptr_t)); +- isc_mem_put(hp->mctx, hp->rl[i], sizeof(*hp->rl[0])); +- } +- isc_mem_put(hp->mctx, hp->hp, isc__hp_max_threads * sizeof(hp->hp[0])); +- isc_mem_put(hp->mctx, hp->rl, isc__hp_max_threads * sizeof(hp->rl[0])); +- +- isc_mem_putanddetach(&hp->mctx, hp, sizeof(*hp)); +-} +- +-void +-isc_hp_clear(isc_hp_t *hp) { +- for (int i = 0; i < hp->max_hps; i++) { +- atomic_store_release(&hp->hp[tid()][i], 0); +- } +-} +- +-void +-isc_hp_clear_one(isc_hp_t *hp, int ihp) { +- atomic_store_release(&hp->hp[tid()][ihp], 0); +-} +- +-uintptr_t +-isc_hp_protect(isc_hp_t *hp, int ihp, atomic_uintptr_t *atom) { +- uintptr_t n = 0; +- uintptr_t ret; +- while ((ret = atomic_load(atom)) != n) { +- atomic_store(&hp->hp[tid()][ihp], ret); +- n = ret; +- } +- return (ret); +-} +- +-uintptr_t +-isc_hp_protect_ptr(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) { +- atomic_store(&hp->hp[tid()][ihp], atomic_load(&ptr)); +- return (atomic_load(&ptr)); +-} +- +-uintptr_t +-isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr) { +- atomic_store_release(&hp->hp[tid()][ihp], atomic_load(&ptr)); +- return (atomic_load(&ptr)); +-} +- +-void +-isc_hp_retire(isc_hp_t *hp, uintptr_t ptr) { +- hp->rl[tid()]->list[hp->rl[tid()]->size++] = ptr; +- INSIST(hp->rl[tid()]->size < isc__hp_max_retired); +- +- if (hp->rl[tid()]->size < HP_THRESHOLD_R) { +- return; +- } +- +- for (int iret = 0; iret < hp->rl[tid()]->size; iret++) { +- uintptr_t obj = hp->rl[tid()]->list[iret]; +- bool can_delete = true; +- for (int itid = 0; itid < isc__hp_max_threads && can_delete; +- itid++) { +- for (int ihp = hp->max_hps - 1; ihp >= 0; ihp--) { +- if (atomic_load(&hp->hp[itid][ihp]) == obj) { +- can_delete = false; +- break; +- } +- } +- } +- +- if (can_delete) { +- size_t bytes = (hp->rl[tid()]->size - iret) * +- sizeof(hp->rl[tid()]->list[0]); +- memmove(&hp->rl[tid()]->list[iret], +- &hp->rl[tid()]->list[iret + 1], bytes); +- hp->rl[tid()]->size--; +- hp->deletefunc((void *)obj); +- } +- } +-} +diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in +index 25b216a..1377172 100644 +--- a/lib/isc/include/isc/Makefile.in ++++ b/lib/isc/include/isc/Makefile.in +@@ -23,13 +23,13 @@ HEADERS = aes.h app.h assertions.h astack.h atomic.h backtrace.h \ + cmocka.h commandline.h counter.h crc64.h deprecated.h \ + endian.h errno.h error.h event.h eventclass.h \ + file.h formatcheck.h fsaccess.h fuzz.h \ +- hash.h heap.h hex.h hmac.h hp.h ht.h httpd.h \ ++ hash.h heap.h hex.h hmac.h ht.h httpd.h \ + interfaceiter.h iterated_hash.h \ + lang.h lex.h lfsr.h lib.h likely.h list.h log.h \ + magic.h managers.h md.h mem.h meminfo.h \ + mutexatomic.h mutexblock.h \ + netaddr.h netmgr.h netscope.h nonce.h os.h parseint.h \ +- pool.h portset.h print.h queue.h quota.h \ ++ pool.h portset.h print.h quota.h \ + radix.h random.h ratelimiter.h refcount.h regex.h \ + region.h resource.h result.h resultclass.h rwlock.h \ + safe.h serial.h siphash.h sockaddr.h socket.h \ +diff --git a/lib/isc/include/isc/hp.h b/lib/isc/include/isc/hp.h +deleted file mode 100644 +index 44155e6..0000000 +--- a/lib/isc/include/isc/hp.h ++++ /dev/null +@@ -1,138 +0,0 @@ +-/* +- * Copyright (C) Internet Systems Consortium, Inc. ("ISC") +- * +- * 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. +- */ +- +-/* +- * Hazard Pointer implementation. +- * +- * This work is based on C++ code available from: +- * https://github.com/pramalhe/ConcurrencyFreaks/ +- * +- * Copyright (c) 2014-2016, Pedro Ramalhete, Andreia Correia +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions are met: +- * +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * * Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * * Neither the name of Concurrency Freaks nor the +- * names of its contributors may be used to endorse or promote products +- * derived from this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +- * THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-#pragma once +- +-#include +-#include +-#include +-#include +-#include +- +-/*% +- * Hazard pointers are a mechanism for protecting objects in memory +- * from being deleted by other threads while in use. This allows +- * safe lock-free data structures. +- * +- * This is an adaptation of the ConcurrencyFreaks implementation in C. +- * More details available at https://github.com/pramalhe/ConcurrencyFreaks, +- * in the file HazardPointers.hpp. +- */ +- +-typedef void(isc_hp_deletefunc_t)(void *); +- +-void +-isc_hp_init(int max_threads); +-/*%< +- * Initialize hazard pointer constants - isc__hp_max_threads. If more threads +- * will try to access hp it will assert. +- */ +- +-isc_hp_t * +-isc_hp_new(isc_mem_t *mctx, size_t max_hps, isc_hp_deletefunc_t *deletefunc); +-/*%< +- * Create a new hazard pointer array of size 'max_hps' (or a reasonable +- * default value if 'max_hps' is 0). The function 'deletefunc' will be +- * used to delete objects protected by hazard pointers when it becomes +- * safe to retire them. +- */ +- +-void +-isc_hp_destroy(isc_hp_t *hp); +-/*%< +- * Destroy a hazard pointer array and clean up all objects protected +- * by hazard pointers. +- */ +- +-void +-isc_hp_clear(isc_hp_t *hp); +-/*%< +- * Clear all hazard pointers in the array for the current thread. +- * +- * Progress condition: wait-free bounded (by max_hps) +- */ +- +-void +-isc_hp_clear_one(isc_hp_t *hp, int ihp); +-/*%< +- * Clear a specified hazard pointer in the array for the current thread. +- * +- * Progress condition: wait-free population oblivious. +- */ +- +-uintptr_t +-isc_hp_protect(isc_hp_t *hp, int ihp, atomic_uintptr_t *atom); +-/*%< +- * Protect an object referenced by 'atom' with a hazard pointer for the +- * current thread. +- * +- * Progress condition: lock-free. +- */ +- +-uintptr_t +-isc_hp_protect_ptr(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr); +-/*%< +- * This returns the same value that is passed as ptr, which is sometimes +- * useful. +- * +- * Progress condition: wait-free population oblivious. +- */ +- +-uintptr_t +-isc_hp_protect_release(isc_hp_t *hp, int ihp, atomic_uintptr_t ptr); +-/*%< +- * Same as isc_hp_protect_ptr(), but explicitly uses memory_order_release. +- * +- * Progress condition: wait-free population oblivious. +- */ +- +-void +-isc_hp_retire(isc_hp_t *hp, uintptr_t ptr); +-/*%< +- * Retire an object that is no longer in use by any thread, calling +- * the delete function that was specified in isc_hp_new(). +- * +- * Progress condition: wait-free bounded (by the number of threads squared) +- */ +diff --git a/lib/isc/include/isc/list.h b/lib/isc/include/isc/list.h +index 4ed1f3c..3e00eda 100644 +--- a/lib/isc/include/isc/list.h ++++ b/lib/isc/include/isc/list.h +@@ -9,8 +9,7 @@ + * information regarding copyright ownership. + */ + +-#ifndef ISC_LIST_H +-#define ISC_LIST_H 1 ++#pragma once + + #include + +@@ -198,4 +197,16 @@ + #define __ISC_LIST_DEQUEUEUNSAFE_TYPE(list, elt, link, type) \ + __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) + +-#endif /* ISC_LIST_H */ ++#define ISC_LIST_MOVEUNSAFE(dest, src) \ ++ { \ ++ (dest).head = (src).head; \ ++ (dest).tail = (src).tail; \ ++ (src).head = NULL; \ ++ (src).tail = NULL; \ ++ } ++ ++#define ISC_LIST_MOVE(dest, src) \ ++ { \ ++ INSIST(ISC_LIST_EMPTY(dest)); \ ++ ISC_LIST_MOVEUNSAFE(dest, src); \ ++ } +diff --git a/lib/isc/include/isc/queue.h b/lib/isc/include/isc/queue.h +deleted file mode 100644 +index a48af88..0000000 +--- a/lib/isc/include/isc/queue.h ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* +- * Copyright (C) Internet Systems Consortium, Inc. ("ISC") +- * +- * 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. +- */ +- +-#pragma once +-#include +- +-typedef struct isc_queue isc_queue_t; +- +-isc_queue_t * +-isc_queue_new(isc_mem_t *mctx, int max_threads); +-/*%< +- * Create a new fetch-and-add array queue. +- * +- * 'max_threads' is currently unused. In the future it can be used +- * to pass a maximum threads parameter when creating hazard pointers, +- * but currently `isc_hp_t` uses a hard-coded value. +- */ +- +-void +-isc_queue_enqueue(isc_queue_t *queue, uintptr_t item); +-/*%< +- * Enqueue an object pointer 'item' at the tail of the queue. +- * +- * Requires: +- * \li 'item' is not null. +- */ +- +-uintptr_t +-isc_queue_dequeue(isc_queue_t *queue); +-/*%< +- * Remove an object pointer from the head of the queue and return the +- * pointer. If the queue is empty, return `nulluintptr` (the uintptr_t +- * representation of NULL). +- * +- * Requires: +- * \li 'queue' is not null. +- */ +- +-void +-isc_queue_destroy(isc_queue_t *queue); +-/*%< +- * Destroy a queue. +- * +- * Requires: +- * \li 'queue' is not null. +- */ +diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h +index 485a80c..baaef93 100644 +--- a/lib/isc/include/isc/types.h ++++ b/lib/isc/include/isc/types.h +@@ -44,11 +44,9 @@ typedef struct isc_counter isc_counter_t; /*%< Counter */ + typedef int16_t isc_dscp_t; /*%< Diffserv code point */ + typedef struct isc_event isc_event_t; /*%< Event */ + typedef ISC_LIST(isc_event_t) isc_eventlist_t; /*%< Event List */ +-typedef unsigned int isc_eventtype_t; /*%< Event Type */ +-typedef uint32_t isc_fsaccess_t; /*%< FS Access */ +-typedef struct isc_hash isc_hash_t; /*%< Hash */ +-typedef struct isc_hp isc_hp_t; /*%< Hazard +- * pointer */ ++typedef unsigned int isc_eventtype_t; /*%< Event Type */ ++typedef uint32_t isc_fsaccess_t; /*%< FS Access */ ++typedef struct isc_hash isc_hash_t; /*%< Hash */ + typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */ + typedef void(isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function + */ +diff --git a/lib/isc/managers.c b/lib/isc/managers.c +index c39a650..e210ad6 100644 +--- a/lib/isc/managers.c ++++ b/lib/isc/managers.c +@@ -9,7 +9,6 @@ + * information regarding copyright ownership. + */ + +-#include + #include + #include + +@@ -23,12 +22,6 @@ isc_managers_create(isc_mem_t *mctx, size_t workers, size_t quantum, + isc_taskmgr_t *taskmgr = NULL; + isc_nm_t *netmgr = NULL; + +- /* +- * We have ncpus network threads, ncpus old network threads - make +- * it 4x just to be on the safe side. +- */ +- isc_hp_init(4 * workers); +- + REQUIRE(netmgrp != NULL && *netmgrp == NULL); + isc__netmgr_create(mctx, workers, &netmgr); + *netmgrp = netmgr; +diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h +index 80de758..097725c 100644 +--- a/lib/isc/netmgr/netmgr-int.h ++++ b/lib/isc/netmgr/netmgr-int.h +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -171,6 +170,17 @@ typedef enum { + NETIEVENT_MAX = 4, + } netievent_type_t; + ++typedef struct isc__nm_uvreq isc__nm_uvreq_t; ++typedef struct isc__netievent isc__netievent_t; ++ ++typedef ISC_LIST(isc__netievent_t) isc__netievent_list_t; ++ ++typedef struct ievent { ++ isc_mutex_t lock; ++ isc_condition_t cond; ++ isc__netievent_list_t list; ++} ievent_t; ++ + /* + * Single network event loop worker. + */ +@@ -180,13 +190,10 @@ typedef struct isc__networker { + uv_loop_t loop; /* libuv loop structure */ + uv_async_t async; /* async channel to send + * data to this networker */ +- isc_mutex_t lock; + bool paused; + bool finished; + isc_thread_t thread; +- isc_queue_t *ievents[NETIEVENT_MAX]; +- atomic_uint_fast32_t nievents[NETIEVENT_MAX]; +- isc_condition_t cond_prio; ++ ievent_t ievents[NETIEVENT_MAX]; + + isc_refcount_t references; + atomic_int_fast64_t pktcount; +@@ -373,11 +380,12 @@ isc__nm_put_netievent(isc_nm_t *mgr, void *ievent); + * either in netmgr.c or matching protocol file (e.g. udp.c, tcp.c, etc.) + */ + +-#define NETIEVENT__SOCKET \ +- isc__netievent_type type; \ +- isc_nmsocket_t *sock; \ +- const char *file; \ +- unsigned int line; \ ++#define NETIEVENT__SOCKET \ ++ isc__netievent_type type; \ ++ ISC_LINK(isc__netievent_t) link; \ ++ isc_nmsocket_t *sock; \ ++ const char *file; \ ++ unsigned int line; \ + const char *func + + typedef struct isc__netievent__socket { +@@ -441,8 +449,7 @@ typedef struct isc__netievent__socket_req { + } + + typedef struct isc__netievent__socket_req_result { +- isc__netievent_type type; +- isc_nmsocket_t *sock; ++ NETIEVENT__SOCKET; + isc__nm_uvreq_t *req; + isc_result_t result; + } isc__netievent__socket_req_result_t; +@@ -541,6 +548,7 @@ typedef struct isc__netievent__socket_quota { + + typedef struct isc__netievent__task { + isc__netievent_type type; ++ ISC_LINK(isc__netievent_t) link; + isc_task_t *task; + } isc__netievent__task_t; + +@@ -577,6 +585,7 @@ typedef struct isc__netievent_udpsend { + + typedef struct isc__netievent { + isc__netievent_type type; ++ ISC_LINK(isc__netievent_t) link; + } isc__netievent_t; + + #define NETIEVENT_TYPE(type) typedef isc__netievent_t isc__netievent_##type##_t; +diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c +index 1aa249e..7261f20 100644 +--- a/lib/isc/netmgr/netmgr.c ++++ b/lib/isc/netmgr/netmgr.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -144,6 +145,7 @@ static isc_threadresult_t + nm_thread(isc_threadarg_t worker0); + static void + async_cb(uv_async_t *handle); ++ + static bool + process_netievent(isc__networker_t *worker, isc__netievent_t *ievent); + static isc_result_t +@@ -153,51 +155,6 @@ wait_for_priority_queue(isc__networker_t *worker); + static void + drain_queue(isc__networker_t *worker, netievent_type_t type); + +-#define ENQUEUE_NETIEVENT(worker, queue, event) \ +- isc_queue_enqueue(worker->ievents[queue], (uintptr_t)event) +-#define DEQUEUE_NETIEVENT(worker, queue) \ +- (isc__netievent_t *)isc_queue_dequeue(worker->ievents[queue]) +- +-#define ENQUEUE_PRIORITY_NETIEVENT(worker, event) \ +- ENQUEUE_NETIEVENT(worker, NETIEVENT_PRIORITY, event) +-#define ENQUEUE_PRIVILEGED_NETIEVENT(worker, event) \ +- ENQUEUE_NETIEVENT(worker, NETIEVENT_PRIVILEGED, event) +-#define ENQUEUE_TASK_NETIEVENT(worker, event) \ +- ENQUEUE_NETIEVENT(worker, NETIEVENT_TASK, event) +-#define ENQUEUE_NORMAL_NETIEVENT(worker, event) \ +- ENQUEUE_NETIEVENT(worker, NETIEVENT_NORMAL, event) +- +-#define DEQUEUE_PRIORITY_NETIEVENT(worker) \ +- DEQUEUE_NETIEVENT(worker, NETIEVENT_PRIORITY) +-#define DEQUEUE_PRIVILEGED_NETIEVENT(worker) \ +- DEQUEUE_NETIEVENT(worker, NETIEVENT_PRIVILEGED) +-#define DEQUEUE_TASK_NETIEVENT(worker) DEQUEUE_NETIEVENT(worker, NETIEVENT_TASK) +-#define DEQUEUE_NORMAL_NETIEVENT(worker) \ +- DEQUEUE_NETIEVENT(worker, NETIEVENT_NORMAL) +- +-#define INCREMENT_NETIEVENT(worker, queue) \ +- atomic_fetch_add_release(&worker->nievents[queue], 1) +-#define DECREMENT_NETIEVENT(worker, queue) \ +- atomic_fetch_sub_release(&worker->nievents[queue], 1) +- +-#define INCREMENT_PRIORITY_NETIEVENT(worker) \ +- INCREMENT_NETIEVENT(worker, NETIEVENT_PRIORITY) +-#define INCREMENT_PRIVILEGED_NETIEVENT(worker) \ +- INCREMENT_NETIEVENT(worker, NETIEVENT_PRIVILEGED) +-#define INCREMENT_TASK_NETIEVENT(worker) \ +- INCREMENT_NETIEVENT(worker, NETIEVENT_TASK) +-#define INCREMENT_NORMAL_NETIEVENT(worker) \ +- INCREMENT_NETIEVENT(worker, NETIEVENT_NORMAL) +- +-#define DECREMENT_PRIORITY_NETIEVENT(worker) \ +- DECREMENT_NETIEVENT(worker, NETIEVENT_PRIORITY) +-#define DECREMENT_PRIVILEGED_NETIEVENT(worker) \ +- DECREMENT_NETIEVENT(worker, NETIEVENT_PRIVILEGED) +-#define DECREMENT_TASK_NETIEVENT(worker) \ +- DECREMENT_NETIEVENT(worker, NETIEVENT_TASK) +-#define DECREMENT_NORMAL_NETIEVENT(worker) \ +- DECREMENT_NETIEVENT(worker, NETIEVENT_NORMAL) +- + static void + isc__nm_async_stop(isc__networker_t *worker, isc__netievent_t *ev0); + static void +@@ -361,12 +318,10 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t nworkers, isc_nm_t **netmgrp) { + r = uv_async_init(&worker->loop, &worker->async, async_cb); + RUNTIME_CHECK(r == 0); + +- isc_mutex_init(&worker->lock); +- isc_condition_init(&worker->cond_prio); +- + for (size_t type = 0; type < NETIEVENT_MAX; type++) { +- worker->ievents[type] = isc_queue_new(mgr->mctx, 128); +- atomic_init(&worker->nievents[type], 0); ++ isc_mutex_init(&worker->ievents[type].lock); ++ isc_condition_init(&worker->ievents[type].cond); ++ ISC_LIST_INIT(worker->ievents[type].list); + } + + worker->recvbuf = isc_mem_get(mctx, ISC_NETMGR_RECVBUF_SIZE); +@@ -417,28 +372,15 @@ nm_destroy(isc_nm_t **mgr0) { + + for (int i = 0; i < mgr->nworkers; i++) { + isc__networker_t *worker = &mgr->workers[i]; +- isc__netievent_t *ievent = NULL; + int r; + +- /* Empty the async event queues */ +- while ((ievent = DEQUEUE_PRIORITY_NETIEVENT(worker)) != NULL) { +- isc__nm_put_netievent(mgr, ievent); +- } +- +- INSIST(DEQUEUE_PRIVILEGED_NETIEVENT(worker) == NULL); +- INSIST(DEQUEUE_TASK_NETIEVENT(worker) == NULL); +- +- while ((ievent = DEQUEUE_NORMAL_NETIEVENT(worker)) != NULL) { +- isc__nm_put_netievent(mgr, ievent); +- } +- isc_condition_destroy(&worker->cond_prio); +- isc_mutex_destroy(&worker->lock); +- + r = uv_loop_close(&worker->loop); + INSIST(r == 0); + + for (size_t type = 0; type < NETIEVENT_MAX; type++) { +- isc_queue_destroy(worker->ievents[type]); ++ INSIST(ISC_LIST_EMPTY(worker->ievents[type].list)); ++ isc_condition_destroy(&worker->ievents[type].cond); ++ isc_mutex_destroy(&worker->ievents[type].lock); + } + + isc_mem_put(mgr->mctx, worker->sendbuf, +@@ -786,13 +728,17 @@ nm_thread(isc_threadarg_t worker0) { + } + + /* +- * We are shutting down. Process the task queues +- * (they may include shutdown events) but do not process +- * the netmgr event queue. ++ * We are shutting down. Drain the queues. + */ + drain_queue(worker, NETIEVENT_PRIVILEGED); + drain_queue(worker, NETIEVENT_TASK); + ++ for (size_t type = 0; type < NETIEVENT_MAX; type++) { ++ LOCK(&worker->ievents[type].lock); ++ INSIST(ISC_LIST_EMPTY(worker->ievents[type].list)); ++ UNLOCK(&worker->ievents[type].lock); ++ } ++ + LOCK(&mgr->lock); + mgr->workers_running--; + SIGNAL(&mgr->wkstatecond); +@@ -814,7 +760,8 @@ process_all_queues(isc__networker_t *worker) { + isc_result_t result = process_queue(worker, type); + switch (result) { + case ISC_R_SUSPEND: +- return (true); ++ reschedule = true; ++ break; + case ISC_R_EMPTY: + /* empty queue */ + break; +@@ -914,35 +861,29 @@ isc__nm_async_task(isc__networker_t *worker, isc__netievent_t *ev0) { + + static void + wait_for_priority_queue(isc__networker_t *worker) { +- isc_condition_t *cond = &worker->cond_prio; +- bool wait_for_work = true; ++ isc_condition_t *cond = &worker->ievents[NETIEVENT_PRIORITY].cond; ++ isc_mutex_t *lock = &worker->ievents[NETIEVENT_PRIORITY].lock; ++ isc__netievent_list_t *list = ++ &(worker->ievents[NETIEVENT_PRIORITY].list); + +- while (true) { +- isc__netievent_t *ievent; +- LOCK(&worker->lock); +- ievent = DEQUEUE_PRIORITY_NETIEVENT(worker); +- if (wait_for_work) { +- while (ievent == NULL) { +- WAIT(cond, &worker->lock); +- ievent = DEQUEUE_PRIORITY_NETIEVENT(worker); +- } +- } +- UNLOCK(&worker->lock); +- wait_for_work = false; +- +- if (ievent == NULL) { +- return; +- } +- DECREMENT_PRIORITY_NETIEVENT(worker); +- +- (void)process_netievent(worker, ievent); ++ LOCK(lock); ++ while (ISC_LIST_EMPTY(*list)) { ++ WAIT(cond, lock); + } ++ UNLOCK(lock); ++ ++ drain_queue(worker, NETIEVENT_PRIORITY); + } + + static void + drain_queue(isc__networker_t *worker, netievent_type_t type) { +- while (process_queue(worker, type) != ISC_R_EMPTY) { +- ; ++ bool empty = false; ++ while (!empty) { ++ if (process_queue(worker, type) == ISC_R_EMPTY) { ++ LOCK(&worker->ievents[type].lock); ++ empty = ISC_LIST_EMPTY(worker->ievents[type].list); ++ UNLOCK(&worker->ievents[type].lock); ++ } + } + } + +@@ -1025,40 +966,41 @@ process_netievent(isc__networker_t *worker, isc__netievent_t *ievent) { + + static isc_result_t + process_queue(isc__networker_t *worker, netievent_type_t type) { +- /* +- * The number of items on the queue is only loosely synchronized with +- * the items on the queue. But there's a guarantee that if there's an +- * item on the queue, it will be accounted for. However there's a +- * possibility that the counter might be higher than the items on the +- * queue stored. +- */ +- uint_fast32_t waiting = atomic_load_acquire(&worker->nievents[type]); +- isc__netievent_t *ievent = DEQUEUE_NETIEVENT(worker, type); ++ isc__netievent_t *ievent = NULL; ++ isc__netievent_list_t list; ++ ++ ISC_LIST_INIT(list); + +- if (ievent == NULL && waiting == 0) { ++ LOCK(&worker->ievents[type].lock); ++ ISC_LIST_MOVE(list, worker->ievents[type].list); ++ UNLOCK(&worker->ievents[type].lock); ++ ++ ievent = ISC_LIST_HEAD(list); ++ if (ievent == NULL) { + /* There's nothing scheduled */ + return (ISC_R_EMPTY); +- } else if (ievent == NULL) { +- /* There's at least one item scheduled, but not on the queue yet +- */ +- return (ISC_R_SUCCESS); + } + + while (ievent != NULL) { +- DECREMENT_NETIEVENT(worker, type); +- bool stop = !process_netievent(worker, ievent); +- +- if (stop) { +- /* Netievent told us to stop */ ++ isc__netievent_t *next = ISC_LIST_NEXT(ievent, link); ++ ISC_LIST_DEQUEUE(list, ievent, link); ++ ++ if (!process_netievent(worker, ievent)) { ++ /* The netievent told us to stop */ ++ if (!ISC_LIST_EMPTY(list)) { ++ /* ++ * Reschedule the rest of the unprocessed ++ * events. ++ */ ++ LOCK(&worker->ievents[type].lock); ++ ISC_LIST_PREPENDLIST(worker->ievents[type].list, ++ list, link); ++ UNLOCK(&worker->ievents[type].lock); ++ } + return (ISC_R_SUSPEND); + } + +- if (waiting-- == 0) { +- /* We reached this round "quota" */ +- break; +- } +- +- ievent = DEQUEUE_NETIEVENT(worker, type); ++ ievent = next; + } + + /* We processed at least one */ +@@ -1070,6 +1012,7 @@ isc__nm_get_netievent(isc_nm_t *mgr, isc__netievent_type type) { + isc__netievent_storage_t *event = isc_mempool_get(mgr->evpool); + + *event = (isc__netievent_storage_t){ .ni.type = type }; ++ ISC_LINK_INIT(&(event->ni), link); + return (event); + } + +@@ -1137,26 +1080,39 @@ isc__nm_maybe_enqueue_ievent(isc__networker_t *worker, + + void + isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event) { ++ netievent_type_t type; ++ + if (event->type > netievent_prio) { +- /* +- * We need to make sure this signal will be delivered and +- * the queue will be processed. +- */ +- LOCK(&worker->lock); +- INCREMENT_PRIORITY_NETIEVENT(worker); +- ENQUEUE_PRIORITY_NETIEVENT(worker, event); +- SIGNAL(&worker->cond_prio); +- UNLOCK(&worker->lock); +- } else if (event->type == netievent_privilegedtask) { +- INCREMENT_PRIVILEGED_NETIEVENT(worker); +- ENQUEUE_PRIVILEGED_NETIEVENT(worker, event); +- } else if (event->type == netievent_task) { +- INCREMENT_TASK_NETIEVENT(worker); +- ENQUEUE_TASK_NETIEVENT(worker, event); ++ type = NETIEVENT_PRIORITY; + } else { +- INCREMENT_NORMAL_NETIEVENT(worker); +- ENQUEUE_NORMAL_NETIEVENT(worker, event); ++ switch (event->type) { ++ case netievent_prio: ++ INSIST(0); ++ ISC_UNREACHABLE(); ++ break; ++ case netievent_privilegedtask: ++ type = NETIEVENT_PRIVILEGED; ++ break; ++ case netievent_task: ++ type = NETIEVENT_TASK; ++ break; ++ default: ++ type = NETIEVENT_NORMAL; ++ break; ++ } + } ++ ++ /* ++ * We need to make sure this signal will be delivered and ++ * the queue will be processed. ++ */ ++ LOCK(&worker->ievents[type].lock); ++ ISC_LIST_ENQUEUE(worker->ievents[type].list, event, link); ++ if (type == NETIEVENT_PRIORITY) { ++ SIGNAL(&worker->ievents[type].cond); ++ } ++ UNLOCK(&worker->ievents[type].lock); ++ + uv_async_send(&worker->async); + } + +@@ -2851,6 +2807,7 @@ shutdown_walk_cb(uv_handle_t *handle, void *arg) { + void + isc__nm_async_shutdown(isc__networker_t *worker, isc__netievent_t *ev0) { + UNUSED(ev0); ++ + uv_walk(&worker->loop, shutdown_walk_cb, NULL); + } + +diff --git a/lib/isc/queue.c b/lib/isc/queue.c +deleted file mode 100644 +index d16c8e6..0000000 +--- a/lib/isc/queue.c ++++ /dev/null +@@ -1,232 +0,0 @@ +-/* +- * Copyright (C) Internet Systems Consortium, Inc. ("ISC") +- * +- * 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. +- */ +- +-#include +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define BUFFER_SIZE 1024 +- +-#define MAX_THREADS 128 +- +-#define ALIGNMENT 128 +- +-static uintptr_t nulluintptr = (uintptr_t)NULL; +- +-typedef struct node { +- atomic_uint_fast32_t deqidx; +- atomic_uintptr_t items[BUFFER_SIZE]; +- atomic_uint_fast32_t enqidx; +- atomic_uintptr_t next; +- isc_mem_t *mctx; +-} node_t; +- +-/* we just need one Hazard Pointer */ +-#define HP_TAIL 0 +-#define HP_HEAD 0 +- +-struct isc_queue { +- alignas(ALIGNMENT) atomic_uintptr_t head; +- alignas(ALIGNMENT) atomic_uintptr_t tail; +- isc_mem_t *mctx; +- int max_threads; +- int taken; +- isc_hp_t *hp; +- void *alloced_ptr; +-}; +- +-static node_t * +-node_new(isc_mem_t *mctx, uintptr_t item) { +- node_t *node = isc_mem_get(mctx, sizeof(*node)); +- *node = (node_t){ .mctx = NULL }; +- +- atomic_init(&node->deqidx, 0); +- atomic_init(&node->enqidx, 1); +- atomic_init(&node->next, 0); +- atomic_init(&node->items[0], item); +- +- for (int i = 1; i < BUFFER_SIZE; i++) { +- atomic_init(&node->items[i], 0); +- } +- +- isc_mem_attach(mctx, &node->mctx); +- +- return (node); +-} +- +-static void +-node_destroy(void *node0) { +- node_t *node = (node_t *)node0; +- +- isc_mem_putanddetach(&node->mctx, node, sizeof(*node)); +-} +- +-static bool +-node_cas_next(node_t *node, node_t *cmp, const node_t *val) { +- return (atomic_compare_exchange_strong(&node->next, (uintptr_t *)&cmp, +- (uintptr_t)val)); +-} +- +-static bool +-queue_cas_tail(isc_queue_t *queue, node_t *cmp, const node_t *val) { +- return (atomic_compare_exchange_strong(&queue->tail, (uintptr_t *)&cmp, +- (uintptr_t)val)); +-} +- +-static bool +-queue_cas_head(isc_queue_t *queue, node_t *cmp, const node_t *val) { +- return (atomic_compare_exchange_strong(&queue->head, (uintptr_t *)&cmp, +- (uintptr_t)val)); +-} +- +-isc_queue_t * +-isc_queue_new(isc_mem_t *mctx, int max_threads) { +- isc_queue_t *queue = NULL; +- node_t *sentinel = NULL; +- void *qbuf = NULL; +- uintptr_t qptr; +- +- /* +- * A trick to allocate an aligned isc_queue_t structure +- */ +- qbuf = isc_mem_get(mctx, sizeof(*queue) + ALIGNMENT); +- qptr = (uintptr_t)qbuf; +- queue = (isc_queue_t *)(qptr + (ALIGNMENT - (qptr % ALIGNMENT))); +- +- if (max_threads == 0) { +- max_threads = MAX_THREADS; +- } +- +- *queue = (isc_queue_t){ +- .max_threads = max_threads, +- .alloced_ptr = qbuf, +- }; +- +- isc_mem_attach(mctx, &queue->mctx); +- +- queue->hp = isc_hp_new(mctx, 1, node_destroy); +- +- sentinel = node_new(mctx, nulluintptr); +- atomic_init(&sentinel->enqidx, 0); +- +- atomic_init(&queue->head, (uintptr_t)sentinel); +- atomic_init(&queue->tail, (uintptr_t)sentinel); +- +- return (queue); +-} +- +-void +-isc_queue_enqueue(isc_queue_t *queue, uintptr_t item) { +- REQUIRE(item != nulluintptr); +- +- while (true) { +- node_t *lt = NULL; +- uint_fast32_t idx; +- uintptr_t n = nulluintptr; +- +- lt = (node_t *)isc_hp_protect(queue->hp, 0, &queue->tail); +- idx = atomic_fetch_add(<->enqidx, 1); +- if (idx > BUFFER_SIZE - 1) { +- node_t *lnext = NULL; +- +- if (lt != (node_t *)atomic_load(&queue->tail)) { +- continue; +- } +- +- lnext = (node_t *)atomic_load(<->next); +- if (lnext == NULL) { +- node_t *newnode = node_new(queue->mctx, item); +- if (node_cas_next(lt, NULL, newnode)) { +- queue_cas_tail(queue, lt, newnode); +- isc_hp_clear(queue->hp); +- return; +- } +- node_destroy(newnode); +- } else { +- queue_cas_tail(queue, lt, lnext); +- } +- +- continue; +- } +- +- if (atomic_compare_exchange_strong(<->items[idx], &n, item)) { +- isc_hp_clear(queue->hp); +- return; +- } +- } +-} +- +-uintptr_t +-isc_queue_dequeue(isc_queue_t *queue) { +- REQUIRE(queue != NULL); +- +- while (true) { +- node_t *lh = NULL; +- uint_fast32_t idx; +- uintptr_t item; +- +- lh = (node_t *)isc_hp_protect(queue->hp, 0, &queue->head); +- if (atomic_load(&lh->deqidx) >= atomic_load(&lh->enqidx) && +- atomic_load(&lh->next) == nulluintptr) +- { +- break; +- } +- +- idx = atomic_fetch_add(&lh->deqidx, 1); +- if (idx > BUFFER_SIZE - 1) { +- node_t *lnext = (node_t *)atomic_load(&lh->next); +- if (lnext == NULL) { +- break; +- } +- if (queue_cas_head(queue, lh, lnext)) { +- isc_hp_retire(queue->hp, (uintptr_t)lh); +- } +- +- continue; +- } +- +- item = atomic_exchange(&(lh->items[idx]), +- (uintptr_t)&queue->taken); +- if (item == nulluintptr) { +- continue; +- } +- +- isc_hp_clear(queue->hp); +- return (item); +- } +- +- isc_hp_clear(queue->hp); +- return (nulluintptr); +-} +- +-void +-isc_queue_destroy(isc_queue_t *queue) { +- node_t *last = NULL; +- void *alloced = NULL; +- +- REQUIRE(queue != NULL); +- +- while (isc_queue_dequeue(queue) != nulluintptr) { +- /* do nothing */ +- } +- +- last = (node_t *)atomic_load_relaxed(&queue->head); +- node_destroy(last); +- isc_hp_destroy(queue->hp); +- +- alloced = queue->alloced_ptr; +- isc_mem_putanddetach(&queue->mctx, alloced, sizeof(*queue) + ALIGNMENT); +-} +diff --git a/lib/isc/task.c b/lib/isc/task.c +index caf2c06..19a657a 100644 +--- a/lib/isc/task.c ++++ b/lib/isc/task.c +@@ -198,7 +198,7 @@ isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, + isc_result_t + isc_task_create_bound(isc_taskmgr_t *manager, unsigned int quantum, + isc_task_t **taskp, int threadid) { +- isc_task_t *task; ++ isc_task_t *task = NULL; + bool exiting; + + REQUIRE(VALID_MANAGER(manager)); +diff --git a/lib/isc/tests/netmgr_test.c b/lib/isc/tests/netmgr_test.c +index d2c19e8..a3c635e 100644 +--- a/lib/isc/tests/netmgr_test.c ++++ b/lib/isc/tests/netmgr_test.c +@@ -21,7 +21,6 @@ + #define UNIT_TESTING + #include + +-#include + #include + #include + #include +diff --git a/lib/isc/win32/libisc.def.in b/lib/isc/win32/libisc.def.in +index 54c6b0b..4f7f374 100644 +--- a/lib/isc/win32/libisc.def.in ++++ b/lib/isc/win32/libisc.def.in +@@ -249,15 +249,6 @@ isc_heap_insert + isc_hex_decodestring + isc_hex_tobuffer + isc_hex_totext +-isc_hp_clear +-isc_hp_clear_one +-isc_hp_destroy +-isc_hp_init +-isc_hp_protect +-isc_hp_protect_ptr +-isc_hp_protect_release +-isc_hp_new +-isc_hp_retire + isc_hmac + isc_hmac_new + isc_hmac_free +@@ -268,13 +259,6 @@ isc_hmac_final + isc_hmac_get_md_type + isc_hmac_get_size + isc_hmac_get_block_size +-isc_hp_new +-isc_hp_destroy +-isc_hp_clear +-isc_hp_protect +-isc_hp_protect_ptr +-isc_hp_protect_release +-isc_hp_retire + isc_ht_add + isc_ht_count + isc_ht_delete +@@ -513,10 +497,6 @@ isc_portset_isset + isc_portset_nports + isc_portset_remove + isc_portset_removerange +-isc_queue_enqueue +-isc_queue_dequeue +-isc_queue_destroy +-isc_queue_new + isc_quota_attach + isc_quota_attach_cb + isc_quota_cb_init +-- +2.33.0 + diff --git a/backport-Test-dnssec-policy-max-zone-ttl-rejects-zone-with-to.patch b/backport-Test-dnssec-policy-max-zone-ttl-rejects-zone-with-to.patch new file mode 100644 index 0000000..2b3aee8 --- /dev/null +++ b/backport-Test-dnssec-policy-max-zone-ttl-rejects-zone-with-to.patch @@ -0,0 +1,107 @@ +From 2022384b8dc7249671d521dc9ef5a292a960521d Mon Sep 17 00:00:00 2001 +From: Matthijs Mekking +Date: Wed, 13 Jul 2022 10:27:18 +0200 +Subject: [PATCH] Test dnssec-policy max-zone-ttl rejects zone with too high + TTL + +Similar to the 'max-zone-ttl' zone option, the 'dnssec-policy' option +should reject zones with TTLs that are out of range. +Conflict: NA +Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/2022384b8dc7249671d521dc9ef5a292a960521d +--- + bin/tests/system/kasp/ns3/named.conf.in | 9 +++++++ + .../system/kasp/ns3/policies/kasp.conf.in | 4 ++++ + bin/tests/system/kasp/ns3/setup.sh | 24 ++++++++----------- + bin/tests/system/kasp/tests.sh | 9 +++++++ + 4 files changed, 32 insertions(+), 14 deletions(-) + +diff --git a/bin/tests/system/kasp/ns3/named.conf.in b/bin/tests/system/kasp/ns3/named.conf.in +index e229fd9158..64ae2aa402 100644 +--- a/bin/tests/system/kasp/ns3/named.conf.in ++++ b/bin/tests/system/kasp/ns3/named.conf.in +@@ -223,6 +223,15 @@ zone "ecdsa384.kasp" { + dnssec-policy "ecdsa384"; + }; + ++/* ++ * Zone with too high TTL. ++ */ ++zone "max-zone-ttl.kasp" { ++ type primary; ++ file "max-zone-ttl.kasp.db"; ++ dnssec-policy "ttl"; ++}; ++ + /* + * Zones in different signing states. + */ +diff --git a/bin/tests/system/kasp/ns3/policies/kasp.conf.in b/bin/tests/system/kasp/ns3/policies/kasp.conf.in +index d0ae96ce08..17b900c7b3 100644 +--- a/bin/tests/system/kasp/ns3/policies/kasp.conf.in ++++ b/bin/tests/system/kasp/ns3/policies/kasp.conf.in +@@ -132,3 +132,7 @@ dnssec-policy "checkds-csk" { + csk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; + }; ++ ++dnssec-policy "ttl" { ++ max-zone-ttl 299; ++}; +diff --git a/bin/tests/system/kasp/ns3/setup.sh b/bin/tests/system/kasp/ns3/setup.sh +index 21c4c9126d..bc4a0fc11d 100644 +--- a/bin/tests/system/kasp/ns3/setup.sh ++++ b/bin/tests/system/kasp/ns3/setup.sh +@@ -64,20 +64,16 @@ if [ -f ../ed448-supported.file ]; then + cat ed448.conf >> named.conf + fi + +-# Set up zone that stays unsigned. +-zone="unsigned.kasp" +-echo_i "setting up zone: $zone" +-zonefile="${zone}.db" +-infile="${zone}.db.infile" +-cp template.db.in $infile +-cp template.db.in $zonefile +- +-# Set up zone that stays unsigned. +-zone="insecure.kasp" +-echo_i "setting up zone: $zone" +-zonefile="${zone}.db" +-infile="${zone}.db.infile" +-cp template.db.in $zonefile ++# Set up zones that stay unsigned. ++for zn in unsigned insecure max-zone-ttl ++do ++ zone="${zn}.kasp" ++ echo_i "setting up zone: $zone" ++ zonefile="${zone}.db" ++ infile="${zone}.db.infile" ++ cp template.db.in $infile ++ cp template.db.in $zonefile ++done + + # Some of these zones already have keys. + zone="dnssec-keygen.kasp" +diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh +index 4a458945a0..ff4d32cc7b 100644 +--- a/bin/tests/system/kasp/tests.sh ++++ b/bin/tests/system/kasp/tests.sh +@@ -253,6 +253,15 @@ status=$((status+ret)) + + next_key_event_threshold=$((next_key_event_threshold+i)) + ++# Test max-zone-ttl rejects zones with too high TTL. ++n=$((n+1)) ++echo_i "check that max-zone-ttl rejects zones with too high TTL ($n)" ++ret=0 ++set_zone "max-zone-ttl.kasp" ++grep "loading from master file ${ZONE}.db failed: out of range" "ns3/named.run" > /dev/null || ret=1 ++test "$ret" -eq 0 || echo_i "failed" ++status=$((status+ret)) ++ + # + # Zone: default.kasp. + # +-- +2.27.0 + diff --git a/backport-fix-an-incorrect-detach-in-update-processing.patch b/backport-fix-an-incorrect-detach-in-update-processing.patch index a62bfff..acc0c7e 100644 --- a/backport-fix-an-incorrect-detach-in-update-processing.patch +++ b/backport-fix-an-incorrect-detach-in-update-processing.patch @@ -14,10 +14,10 @@ Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/17924f4bdfbd99e060 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/ns/update.c b/lib/ns/update.c -index db04e60..071de25 100644 +index c4bde3d4eb..a21b725f39 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c -@@ -1743,19 +1743,17 @@ respond(ns_client_t *client, isc_result_t result) { +@@ -1569,19 +1569,17 @@ respond(ns_client_t *client, isc_result_t result) { msg_result = dns_message_reply(client->message, true); if (msg_result != ISC_R_SUCCESS) { @@ -45,7 +45,7 @@ index db04e60..071de25 100644 isc_nmhandle_detach(&client->reqhandle); } -@@ -1769,7 +1767,8 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle, +@@ -1595,7 +1593,8 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle, dns_zone_t *zone = NULL, *raw = NULL; /* @@ -55,7 +55,7 @@ index db04e60..071de25 100644 */ isc_nmhandle_attach(handle, &client->reqhandle); -@@ -1848,8 +1847,6 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle, +@@ -1677,8 +1676,6 @@ ns_update_start(ns_client_t *client, isc_nmhandle_t *handle, default: FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); } @@ -64,7 +64,7 @@ index db04e60..071de25 100644 return; failure: -@@ -1872,7 +1869,6 @@ failure: +@@ -1696,7 +1693,6 @@ failure: if (zone != NULL) { dns_zone_detach(&zone); } @@ -72,14 +72,13 @@ index db04e60..071de25 100644 } /*% -@@ -3598,6 +3594,7 @@ forward_done(isc_task_t *task, isc_event_t *event) { - - isc_quota_detach(&(isc_quota_t *){ &client->manager->sctx->updquota }); +@@ -3554,6 +3550,7 @@ forward_done(isc_task_t *task, isc_event_t *event) { + ns_client_sendraw(client, uev->answer); + dns_message_detach(&uev->answer); isc_event_free(&event); + isc_nmhandle_detach(&client->reqhandle); isc_nmhandle_detach(&client->updatehandle); } -- -2.27.0 - +2.23.0 \ No newline at end of file diff --git a/backport-warn-about-zones-with-both-dnssec-policy-and-max-zon.patch b/backport-warn-about-zones-with-both-dnssec-policy-and-max-zon.patch new file mode 100644 index 0000000..eb051d6 --- /dev/null +++ b/backport-warn-about-zones-with-both-dnssec-policy-and-max-zon.patch @@ -0,0 +1,102 @@ +From fb8f102ffcd0e0bb3b9691ceec5ee8a24025af28 Mon Sep 17 00:00:00 2001 +From: Evan Hunt +Date: Thu, 21 Jul 2022 11:07:31 -0700 +Subject: [PATCH] warn about zones with both dnssec-policy and max-zone-ttl + +max-zone-ttl in zone/view/options is a no-op if dnssec-policy +is in use, so generate a warning. +Conflict: NA +Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/fb8f102ffcd0e0bb3b9691ceec5ee8a24025af28 +--- + bin/tests/system/checkconf/tests.sh | 8 ++++++ + .../checkconf/warn-kasp-max-zone-ttl.conf | 26 +++++++++++++++++++ + lib/bind9/check.c | 21 +++++++++++++++ + 3 files changed, 55 insertions(+) + create mode 100644 bin/tests/system/checkconf/warn-kasp-max-zone-ttl.conf + +diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh +index cec8f8407e..9143e9e08c 100644 +--- a/bin/tests/system/checkconf/tests.sh ++++ b/bin/tests/system/checkconf/tests.sh +@@ -585,6 +585,14 @@ grep "not recommended" < checkconf.out$n > /dev/null || ret=1 + if [ $ret != 0 ]; then echo_i "failed"; ret=1; fi + status=`expr $status + $ret` + ++n=`expr $n + 1` ++echo_i "check that using both max-zone-ttl and dnssec-policy generates a warning ($n)" ++ret=0 ++$CHECKCONF warn-kasp-max-zone-ttl.conf > checkconf.out$n 2>/dev/null || ret=1 ++grep "option 'max-zone-ttl' is ignored when used together with 'dnssec-policy'" < checkconf.out$n > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo_i "failed"; ret=1; fi ++status=`expr $status + $ret` ++ + n=$((n+1)) + echo_i "check that masterfile-format map generates deprecation warning ($n)" + ret=0 +diff --git a/bin/tests/system/checkconf/warn-kasp-max-zone-ttl.conf b/bin/tests/system/checkconf/warn-kasp-max-zone-ttl.conf +new file mode 100644 +index 0000000000..0b5939478e +--- /dev/null ++++ b/bin/tests/system/checkconf/warn-kasp-max-zone-ttl.conf +@@ -0,0 +1,26 @@ ++/* ++ * 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. ++ */ ++ ++/* ++ * The dnssec-policy is not defined. Should also be caught if it is inherited. ++ */ ++ ++options { ++ dnssec-policy default; ++}; ++ ++zone "example.net" { ++ type primary; ++ file "example.db"; ++ max-zone-ttl 600; ++}; +diff --git a/lib/bind9/check.c b/lib/bind9/check.c +index 0be4871020..0707ea44b9 100644 +--- a/lib/bind9/check.c ++++ b/lib/bind9/check.c +@@ -2633,6 +2633,27 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions, + } + } + ++ /* ++ * Warn about zones with both dnssec-policy and max-zone-ttl ++ */ ++ if (has_dnssecpolicy) { ++ obj = NULL; ++ (void)cfg_map_get(zoptions, "max-zone-ttl", &obj); ++ if (obj == NULL && voptions != NULL) { ++ (void)cfg_map_get(voptions, "max-zone-ttl", &obj); ++ } ++ if (obj == NULL && goptions != NULL) { ++ (void)cfg_map_get(goptions, "max-zone-ttl", &obj); ++ } ++ if (obj != NULL) { ++ cfg_obj_log(obj, logctx, ISC_LOG_WARNING, ++ "zone '%s': option 'max-zone-ttl' " ++ "is ignored when used together with " ++ "'dnssec-policy'", ++ znamestr); ++ } ++ } ++ + /* + * Check validity of the zone options. + */ +-- +2.27.0 + diff --git a/bind.spec b/bind.spec index 7fe5e70..d2a96cf 100644 --- a/bind.spec +++ b/bind.spec @@ -30,7 +30,7 @@ Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv Name: bind License: MPLv2.0 Version: 9.16.23 -Release: 21 +Release: 22 Epoch: 32 Url: https://www.isc.org/downloads/bind/ # @@ -167,66 +167,78 @@ Patch6093:backport-Increase-the-BUFSIZ-long-buffers.patch Patch6094:backport-Inherit-dnssec-policy-in-check-for-inline-signing.patch Patch6095:backport-Reject-zones-with-TTL-higher-than-dnssec-policy-max.patch -Patch6002:backport-CVE-2022-2795.patch -Patch6003:backport-CVE-2022-3080.patch -Patch6004:backport-CVE-2022-38177.patch -Patch6005:backport-CVE-2022-38178.patch -Patch6006:backport-CVE-2022-2906.patch -Patch6007:backport-CVE-2022-2881.patch -Patch6096:backport-CVE-2022-3736.patch -Patch6097:backport-CVE-2022-3924.patch -Patch6098:backport-CVE-2022-3094-add-an-update-quota.patch -Patch6099:backport-CVE-2022-3094-add-a-configuration-option-for-the-update-quota.patch -Patch6100:backport-CVE-2022-3094-move-update-ACL-and-update-policy-checks-before-quota.patch - -Patch6101:backport-Fix-a-logical-bug-in-cfg_print_duration.patch -Patch6102:backport-ensure-RPZ-lookups-handle-CD-1-correctly.patch -Patch6103:backport-Don-t-allow-DNSSEC-records-in-the-raw-zone.patch -Patch6104:backport-Select-the-appropriate-namespace-when-using-a-dual-stack-server.patch -Patch6105:backport-Check-for-NULL-before-dereferencing-qctx-rpz_st.patch -Patch6106:backport-Suppress-duplicate-dns_db_updatenotify_register-registrations.patch -Patch6107:backport-Call-dns_db_updatenotify_unregister-earlier.patch -Patch6108:backport-Add-missing-DbC-magic-checks.patch -Patch6109:backport-Propagate-the-shutdown-event-to-the-recursing-ns_client-s.patch -Patch6110:backport-Release-unused-key-file-IO-lock-objects.patch -Patch6111:backport-Fix-logging-a-uint32_t-SOA-serial-value-in-dns_catz_update_from_db.patch - -Patch6112:backport-Don-t-perform-arithmetic-on-NULL-pointers.patch -Patch6113:backport-Accept-in-NULL-with-inlen-0-in-isc_-half-siphash24.patch -Patch6114:backport-Fix-a-use-after-free-bug-in-dns_zonemgr_releasezone.patch -Patch6115:backport-Fix-dns_fwdtable_addfwd-error-path-cleanup-bug.patch -Patch6116:backport-Detach-the-views-in-zone_shutdown-not-in-zone_free.patch -Patch6117:backport-Detach-the-zone-views-outside-of-the-zone-lock.patch -Patch6118:backport-delay-trust-anchor-management-until-zones-are-loaded.patch -Patch6119:backport-In-hmac_createctx-free-ctx-on-isc_hmac_init-failure.patch -Patch6120:backport-Fix-dns_kasp_attach-dns_kasp_detach-usage.patch -Patch6121:backport-Fix-backport-error-in-84929d1cd7e1042452094ceeae969324b9df504f.patch -Patch6122:backport-Fix-a-cleanup-bug-when-isc_task_create-fails-in-dns_catz_new_zones.patch -Patch6123:backport-Searching-catzs-zones-requires-a-read-lock.patch -Patch6124:backport-Fix-view-s-zones-reverting-bug-during-reconfiguration.patch - -Patch6125:backport-CVE-2023-2911.patch -Patch6126:backport-CVE-2023-2828.patch -Patch6127:backport-Disable-the-internale-memory-allocator-by-default.patch - -Patch6128:backport-CVE-2023-3341.patch - -Patch6129:backport-Add-mctx-attach-detach-when-creating-destroying-a-memory-pool.patch -Patch6130:backport-Ensure-that-named_server_t-is-properly-initialized.patch -Patch6131:backport-Reset-parser-before-parsing-of-internal-trust-anchor.patch -Patch6132:backport-clean-up-properly-when-interface-creation-fails.patch -Patch6133:backport-dnstap-query_message-field-was-erroneously-set-with-responses.patch -Patch6134:backport-fix-an-incorrect-detach-in-update-processing.patch -Patch6135:backport-nsec3.c-Add-a-missing-dns_db_detachnode-call.patch - -Patch6136:backport-Check-BN_dup-results-in-rsa_check.patch -Patch6137:backport-Check-that-e-and-n-are-allocated-in-opensslrsa_fromdns.patch -Patch6138:backport-Check-that-e-and-n-are-non-NULL-in-opensslrsa_todns.patch -Patch6139:backport-Check-that-primary-key-names-have-not-changed.patch -Patch6140:backport-Fix-memory-leak-in-dns_message_checksig-SIG-0-sigs.patch -Patch6141:backport-Fix-ns_statscounter_recursclients-counting-bug.patch -Patch6142:backport-Free-n-on-error-path-in-rsa_check.patch -Patch6143:backport-Free-rsa-if-e-is-NULL-in-opensslrsa_verify2.patch +Patch6096:backport-Test-dnssec-policy-max-zone-ttl-rejects-zone-with-to.patch +Patch6097:backport-warn-about-zones-with-both-dnssec-policy-and-max-zon.patch + +Patch6098:backport-CVE-2022-2795.patch +Patch6099:backport-CVE-2022-3080.patch +Patch6100:backport-CVE-2022-38177.patch +Patch6101:backport-CVE-2022-38178.patch +Patch6102:backport-CVE-2022-2906.patch +Patch6103:backport-CVE-2022-2881.patch + +Patch6104:backport-Reset-parser-before-parsing-of-internal-trust-anchor.patch +Patch6105:backport-nsec3.c-Add-a-missing-dns_db_detachnode-call.patch +Patch6106:backport-dnstap-query_message-field-was-erroneously-set-with-responses.patch +Patch6107:backport-fix-an-incorrect-detach-in-update-processing.patch +Patch6108:backport-clean-up-properly-when-interface-creation-fails.patch +Patch6109:backport-Add-mctx-attach-detach-when-creating-destroying-a-memory-pool.patch +Patch6110:backport-Ensure-that-named_server_t-is-properly-initialized.patch +Patch6111:backport-Free-rsa-if-e-is-NULL-in-opensslrsa_verify2.patch +Patch6112:backport-Free-n-on-error-path-in-rsa_check.patch +Patch6113:backport-Fix-memory-leak-in-dns_message_checksig-SIG-0-sigs.patch +Patch6114:backport-Check-that-e-and-n-are-non-NULL-in-opensslrsa_todns.patch +Patch6115:backport-Check-that-e-and-n-are-allocated-in-opensslrsa_fromdns.patch +Patch6116:backport-Check-BN_dup-results-in-rsa_check.patch +Patch6117:backport-Check-that-primary-key-names-have-not-changed.patch +Patch6118:backport-Fix-ns_statscounter_recursclients-counting-bug.patch + +Patch6119:backport-Fix-a-logical-bug-in-cfg_print_duration.patch +Patch6120:backport-ensure-RPZ-lookups-handle-CD-1-correctly.patch +Patch6121:backport-Don-t-allow-DNSSEC-records-in-the-raw-zone.patch +Patch6122:backport-Select-the-appropriate-namespace-when-using-a-dual-stack-server.patch +Patch6123:backport-Check-for-NULL-before-dereferencing-qctx-rpz_st.patch +Patch6124:backport-Suppress-duplicate-dns_db_updatenotify_register-registrations.patch +Patch6125:backport-Call-dns_db_updatenotify_unregister-earlier.patch +Patch6126:backport-Add-missing-DbC-magic-checks.patch +Patch6127:backport-Propagate-the-shutdown-event-to-the-recursing-ns_client-s.patch +Patch6128:backport-Release-unused-key-file-IO-lock-objects.patch +Patch6129:backport-Fix-logging-a-uint32_t-SOA-serial-value-in-dns_catz_update_from_db.patch + +Patch6130:backport-CVE-2022-3736.patch +Patch6131:backport-CVE-2022-3924.patch +Patch6132:backport-CVE-2022-3094-add-an-update-quota.patch +Patch6133:backport-CVE-2022-3094-add-a-configuration-option-for-the-update-quota.patch +Patch6134:backport-CVE-2022-3094-move-update-ACL-and-update-policy-checks-before-quota.patch + +Patch6135:backport-Don-t-perform-arithmetic-on-NULL-pointers.patch +Patch6136:backport-Accept-in-NULL-with-inlen-0-in-isc_-half-siphash24.patch +Patch6137:backport-Fix-a-use-after-free-bug-in-dns_zonemgr_releasezone.patch +Patch6138:backport-Fix-dns_fwdtable_addfwd-error-path-cleanup-bug.patch +Patch6139:backport-Detach-the-views-in-zone_shutdown-not-in-zone_free.patch +Patch6140:backport-Detach-the-zone-views-outside-of-the-zone-lock.patch +Patch6141:backport-delay-trust-anchor-management-until-zones-are-loaded.patch +Patch6142:backport-In-hmac_createctx-free-ctx-on-isc_hmac_init-failure.patch +Patch6143:backport-Fix-dns_kasp_attach-dns_kasp_detach-usage.patch +Patch6144:backport-Fix-backport-error-in-84929d1cd7e1042452094ceeae969324b9df504f.patch +Patch6145:backport-Fix-a-cleanup-bug-when-isc_task_create-fails-in-dns_catz_new_zones.patch +Patch6146:backport-Searching-catzs-zones-requires-a-read-lock.patch +Patch6147:backport-Fix-view-s-zones-reverting-bug-during-reconfiguration.patch +Patch6148:backport-Disable-the-internal-memory-allocator-by-default.patch +Patch6149:backport-CVE-2023-2911.patch +Patch6150:backport-CVE-2023-2828.patch + +Patch6151:backport-CVE-2023-3341.patch + +Patch6152:backport-CVE-2023-5679.patch +Patch6153:backport-CVE-2023-5517.patch +Patch6154:backport-CVE-2023-6516.patch + +Patch6155:backport-Make-isc_ht_init-and-isc_ht_iter_create-return-void.patch +Patch6156:backport-CVE-2023-4408.patch + +Patch6157:backport-CVE-2023-50387-CVE-2023-50868.patch +Patch6158:backport-Replace-netievent-lock-free-queue-with-simple-locked.patch Patch9000:bugfix-limit-numbers-of-test-threads.patch @@ -1236,6 +1248,12 @@ fi; %endif %changelog +* Mon Mar 18 2024 chengyechun - 32:9.16.23-22 +- Type:CVE +- CVE:CVE-2023-6516 CVE-2023-4408 CVE-2023-5517 CVE-2023-5680 CVE-2023-5679 CVE-50387 CVE-2023-50868 +- SUG:NA +- DESC:fix CVE-2023-6516 CVE-2023-4408 CVE-2023-5517 CVE-2023-5680 CVE-2023-5679 CVE-50387 CVE-2023-50868 and sync some patches from upstream + * Sat Jan 06 2024 zhanghao - 32:9.16.23-21 - Type:bugfix - CVE:NA -- Gitee