diff --git a/bind-9.11-CVE-2023-50387.patch b/bind-9.11-CVE-2023-50387.patch new file mode 100644 index 0000000..2f90d65 --- /dev/null +++ b/bind-9.11-CVE-2023-50387.patch @@ -0,0 +1,737 @@ +From 4c20ab54ec503f65d8ee0b863cbf41103d95130a Mon Sep 17 00:00:00 2001 +From: Mark Andrews +Date: Wed, 22 Nov 2023 16:59:03 +1100 +Subject: [PATCH] Fail the DNSSEC validation on the first failure + +Be more strict when encountering DNSSEC validation failures - fail on +the first failure. This will break domains that have DNSSEC signing +keys with duplicate key ids, but this is something that's much easier +to fix on the authoritative side, so we are just going to be strict +on the resolver side where it is causing performance problems. + +(cherry picked from commit 8b7ecba9885e163c07c2dd3e1ceab79b2ba89e34) + +Add normal and slow task queues + +Split the task manager queues into normal and slow task queues, so we +can move the tasks that blocks processing for a long time (like DNSSEC +validation) into the slow queue which doesn't block fast +operations (like responding from the cache). This mitigates the whole +class of KeyTrap-like issues. + +(cherry picked from commit db083a21726300916fa0b9fd8a433a796fedf636) + +Don't iterate from start every time we select new signing key + +Improve the selecting of the new signing key by remembering where +we stopped the iteration and just continue from that place instead +of iterating from the start over and over again each time. + +(cherry picked from commit 75faeefcab47e4f1e12b358525190b4be90f97de) + +Optimize selecting the signing key + +Don't parse the crypto data before parsing and matching the id and the +algorithm. + +(cherry picked from commit b38552cca7200a72658e482f8407f57516efc5db) + +6322. [security] Specific DNS answers could cause a denial-of-service + condition due to DNS validation taking a long time. + (CVE-2023-50387) [GL #4424] + + The same code change also addresses another problem: + preparing NSEC3 closest encloser proofs could exhaust + available CPU resources. (CVE-2023-50868) [GL #4459] +--- + lib/dns/dst_api.c | 25 ++++-- + lib/dns/include/dns/validator.h | 1 + + lib/dns/include/dst/dst.h | 4 + + lib/dns/resolver.c | 2 +- + lib/dns/validator.c | 97 +++++++++----------- + lib/dns/win32/libdns.def.in | 1 + + lib/isc/include/isc/task.h | 11 ++- + lib/isc/task.c | 153 ++++++++++++++++++++++---------- + 8 files changed, 186 insertions(+), 108 deletions(-) + +diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c +index 2156384ec1..6bcd99796c 100644 +--- a/lib/dns/dst_api.c ++++ b/lib/dns/dst_api.c +@@ -105,6 +105,7 @@ static isc_result_t frombuffer(dns_name_t *name, + dns_rdataclass_t rdclass, + isc_buffer_t *source, + isc_mem_t *mctx, ++ bool no_rdata, + dst_key_t **keyp); + + static isc_result_t algorithm_status(unsigned int alg); +@@ -764,6 +765,13 @@ isc_result_t + dst_key_fromdns(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(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; +@@ -792,7 +800,7 @@ dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass, + } + + result = frombuffer(name, alg, flags, proto, rdclass, source, +- mctx, &key); ++ mctx, no_rdata, &key); + if (result != ISC_R_SUCCESS) + return (result); + key->key_id = id; +@@ -814,7 +822,7 @@ dst_key_frombuffer(dns_name_t *name, unsigned int alg, + REQUIRE(dst_initialized); + + result = frombuffer(name, alg, flags, protocol, rdclass, source, +- mctx, &key); ++ mctx, false, &key); + if (result != ISC_R_SUCCESS) + return (result); + +@@ -1915,7 +1923,8 @@ computeid(dst_key_t *key) { + static isc_result_t + frombuffer(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; +@@ -1940,10 +1949,12 @@ frombuffer(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 cc4478d6d4..b4bf8f29db 100644 +--- a/lib/dns/include/dns/validator.h ++++ b/lib/dns/include/dns/validator.h +@@ -160,6 +160,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 180c841307..a8be2daf67 100644 +--- a/lib/dns/include/dst/dst.h ++++ b/lib/dns/include/dst/dst.h +@@ -435,6 +435,10 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory); + */ + + isc_result_t ++dst_key_fromdns_ex(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(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 4f71f48039..487107614c 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -9267,7 +9267,7 @@ dns_resolver_create(dns_view_t *view, + if (result != ISC_R_SUCCESS) + goto cleanup_buckets; + res->buckets[i].task = NULL; +- result = isc_task_create(taskmgr, 0, &res->buckets[i].task); ++ result = isc_task_create(taskmgr, ISC_TASK_QUANTUM_SLOW, &res->buckets[i].task); + if (result != ISC_R_SUCCESS) { + DESTROYLOCK(&res->buckets[i].lock); + goto cleanup_buckets; +diff --git a/lib/dns/validator.c b/lib/dns/validator.c +index 2a5c3caa6a..0b257fe874 100644 +--- a/lib/dns/validator.c ++++ b/lib/dns/validator.c +@@ -1207,6 +1207,12 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, + * val->key at it. + * + * If val->key is non-NULL, this returns the next matching key. ++ * 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, ++ * ISC_R_NOTFOUND if not. Any other value indicates error. + */ + static isc_result_t + get_dst_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo, +@@ -1216,54 +1222,59 @@ get_dst_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo, + 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; +- else { +- foundold = false; ++ if (oldkey == NULL) { ++ result = dns_rdataset_first(rdataset); ++ } else { ++ dst_key_free(&oldkey); + val->key = NULL; ++ result = dns_rdataset_next(rdataset); ++ } ++ ++ if (result != ISC_R_SUCCESS) { ++ goto done; + } + +- result = dns_rdataset_first(rdataset); +- if (result != ISC_R_SUCCESS) +- goto failure; + 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); +- if (result == ISC_R_NOMORE) +- result = ISC_R_NOTFOUND; + +- failure: +- if (oldkey != NULL) +- dst_key_free(&oldkey); ++done: ++ if (result == ISC_R_NOMORE) { ++ result = ISC_R_NOTFOUND; ++ } + + return (result); + } +@@ -1633,37 +1644,13 @@ validate(dns_validator_t *val, bool resume) { + continue; + } + +- do { +- vresult = verify(val, val->key, &rdata, +- val->siginfo->keyid); +- if (vresult == ISC_R_SUCCESS) +- break; +- if (val->keynode != NULL) { +- dns_keynode_t *nextnode = NULL; +- result = dns_keytable_findnextkeynode( +- val->keytable, +- val->keynode, +- &nextnode); +- dns_keytable_detachkeynode(val->keytable, +- &val->keynode); +- val->keynode = nextnode; +- if (result != ISC_R_SUCCESS) { +- val->key = NULL; +- break; +- } +- val->key = dns_keynode_key(val->keynode); +- if (val->key == NULL) +- break; +- } else { +- if (get_dst_key(val, val->siginfo, val->keyset) +- != ISC_R_SUCCESS) +- break; +- } +- } while (1); +- if (vresult != ISC_R_SUCCESS) ++ 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 { ++ } else { + dns_rdataset_trimttl(event->rdataset, + event->sigrdataset, + val->siginfo, val->start, +@@ -1700,9 +1687,13 @@ validate(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/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in +index f597049493..7320653439 100644 +--- a/lib/dns/win32/libdns.def.in ++++ b/lib/dns/win32/libdns.def.in +@@ -1439,6 +1439,7 @@ dst_key_format + dst_key_free + dst_key_frombuffer + dst_key_fromdns ++dst_key_fromdns_ex + dst_key_fromfile + dst_key_fromgssapi + dst_key_fromlabel +diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h +index 28e5e25fc6..42f7763869 100644 +--- a/lib/isc/include/isc/task.h ++++ b/lib/isc/include/isc/task.h +@@ -98,8 +98,15 @@ ISC_LANG_BEGINDECLS + ***/ + + typedef enum { +- isc_taskmgrmode_normal = 0, +- isc_taskmgrmode_privileged ++ isc_taskqueue_normal = 0, ++ isc_taskqueue_slow = 1, ++} isc_taskqueue_t; ++ ++#define ISC_TASK_QUANTUM_SLOW 1024 ++ ++typedef enum { ++ isc_taskmgrmode_normal = 0, ++ isc_taskmgrmode_privileged + } isc_taskmgrmode_t; + + /*% Task and task manager methods */ +diff --git a/lib/isc/task.c b/lib/isc/task.c +index 048639350b..cc83269df2 100644 +--- a/lib/isc/task.c ++++ b/lib/isc/task.c +@@ -107,6 +107,7 @@ struct isc__task { + isc_eventlist_t on_shutdown; + unsigned int nevents; + unsigned int quantum; ++ unsigned int qid; + unsigned int flags; + isc_stdtime_t now; + isc_time_t tnow; +@@ -141,11 +142,11 @@ struct isc__taskmgr { + /* Locked by task manager lock. */ + unsigned int default_quantum; + LIST(isc__task_t) tasks; +- isc__tasklist_t ready_tasks; +- isc__tasklist_t ready_priority_tasks; ++ isc__tasklist_t ready_tasks[2]; ++ isc__tasklist_t ready_priority_tasks[2]; + isc_taskmgrmode_t mode; + #ifdef ISC_PLATFORM_USETHREADS +- isc_condition_t work_available; ++ isc_condition_t work_available[2]; + isc_condition_t exclusive_granted; + isc_condition_t paused; + #endif /* ISC_PLATFORM_USETHREADS */ +@@ -247,13 +248,13 @@ isc_taskmgrmode_t + isc__taskmgr_mode(isc_taskmgr_t *manager0); + + static inline bool +-empty_readyq(isc__taskmgr_t *manager); ++empty_readyq(isc__taskmgr_t *manager, isc_taskqueue_t qid); + + static inline isc__task_t * +-pop_readyq(isc__taskmgr_t *manager); ++pop_readyq(isc__taskmgr_t *manager, isc_taskqueue_t qid); + + static inline void +-push_readyq(isc__taskmgr_t *manager, isc__task_t *task); ++push_readyq(isc__taskmgr_t *manager, isc__task_t *task, isc_taskqueue_t qid); + + static struct isc__taskmethods { + isc_taskmethods_t methods; +@@ -324,7 +325,8 @@ task_finished(isc__task_t *task) { + * any idle worker threads so they + * can exit. + */ +- BROADCAST(&manager->work_available); ++ BROADCAST(&manager->work_available[isc_taskqueue_normal]); ++ BROADCAST(&manager->work_available[isc_taskqueue_slow]); + } + #endif /* USE_WORKER_THREADS */ + UNLOCK(&manager->lock); +@@ -364,7 +366,13 @@ isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum, + INIT_LIST(task->events); + INIT_LIST(task->on_shutdown); + task->nevents = 0; +- task->quantum = quantum; ++ if (quantum >= ISC_TASK_QUANTUM_SLOW) { ++ task->qid = isc_taskqueue_slow; ++ task->quantum = quantum - ISC_TASK_QUANTUM_SLOW; ++ } else { ++ task->qid = isc_taskqueue_normal; ++ task->quantum = quantum; ++ } + task->flags = 0; + task->now = 0; + isc_time_settoepoch(&task->tnow); +@@ -476,11 +484,11 @@ task_ready(isc__task_t *task) { + + LOCK(&manager->lock); + LOCK(&task->lock); +- push_readyq(manager, task); ++ push_readyq(manager, task, task->qid); + UNLOCK(&task->lock); + #ifdef USE_WORKER_THREADS + if (manager->mode == isc_taskmgrmode_normal || has_privilege) +- SIGNAL(&manager->work_available); ++ SIGNAL(&manager->work_available[task->qid]); + #endif /* USE_WORKER_THREADS */ + UNLOCK(&manager->lock); + } +@@ -961,13 +969,13 @@ isc__task_getcurrenttimex(isc_task_t *task0, isc_time_t *t) { + * Caller must hold the task manager lock. + */ + static inline bool +-empty_readyq(isc__taskmgr_t *manager) { ++empty_readyq(isc__taskmgr_t *manager, isc_taskqueue_t qid) { + isc__tasklist_t queue; + + if (manager->mode == isc_taskmgrmode_normal) +- queue = manager->ready_tasks; ++ queue = manager->ready_tasks[qid]; + else +- queue = manager->ready_priority_tasks; ++ queue = manager->ready_priority_tasks[qid]; + + return (EMPTY(queue)); + } +@@ -981,18 +989,18 @@ empty_readyq(isc__taskmgr_t *manager) { + * Caller must hold the task manager lock. + */ + static inline isc__task_t * +-pop_readyq(isc__taskmgr_t *manager) { ++pop_readyq(isc__taskmgr_t *manager, isc_taskqueue_t qid) { + isc__task_t *task; + + if (manager->mode == isc_taskmgrmode_normal) +- task = HEAD(manager->ready_tasks); ++ task = HEAD(manager->ready_tasks[qid]); + else +- task = HEAD(manager->ready_priority_tasks); ++ task = HEAD(manager->ready_priority_tasks[qid]); + + if (task != NULL) { +- DEQUEUE(manager->ready_tasks, task, ready_link); ++ DEQUEUE(manager->ready_tasks[qid], task, ready_link); + if (ISC_LINK_LINKED(task, ready_priority_link)) +- DEQUEUE(manager->ready_priority_tasks, task, ++ DEQUEUE(manager->ready_priority_tasks[qid], task, + ready_priority_link); + } + +@@ -1006,16 +1014,16 @@ pop_readyq(isc__taskmgr_t *manager) { + * Caller must hold the task manager lock. + */ + static inline void +-push_readyq(isc__taskmgr_t *manager, isc__task_t *task) { +- ENQUEUE(manager->ready_tasks, task, ready_link); ++push_readyq(isc__taskmgr_t *manager, isc__task_t *task, isc_taskqueue_t qid) { ++ ENQUEUE(manager->ready_tasks[qid], task, ready_link); + if ((task->flags & TASK_F_PRIVILEGED) != 0) +- ENQUEUE(manager->ready_priority_tasks, task, ++ ENQUEUE(manager->ready_priority_tasks[qid], task, + ready_priority_link); + manager->tasks_ready++; + } + + static void +-dispatch(isc__taskmgr_t *manager) { ++dispatch(isc__taskmgr_t *manager, isc_taskqueue_t qid) { + isc__task_t *task; + #ifndef USE_WORKER_THREADS + unsigned int total_dispatch_count = 0; +@@ -1094,13 +1102,13 @@ dispatch(isc__taskmgr_t *manager) { + * If a pause has been requested, don't do any work + * until it's been released. + */ +- while ((empty_readyq(manager) || manager->pause_requested || ++ while ((empty_readyq(manager, qid) || manager->pause_requested || + manager->exclusive_requested) && !FINISHED(manager)) + { + XTHREADTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_WAIT, "wait")); +- WAIT(&manager->work_available, &manager->lock); ++ WAIT(&manager->work_available[qid], &manager->lock); + XTHREADTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TASK, + ISC_MSG_AWAKE, "awake")); +@@ -1113,7 +1121,7 @@ dispatch(isc__taskmgr_t *manager) { + XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK, + ISC_MSG_WORKING, "working")); + +- task = pop_readyq(manager); ++ task = pop_readyq(manager, qid); + if (task != NULL) { + unsigned int dispatch_count = 0; + bool done = false; +@@ -1278,7 +1286,7 @@ dispatch(isc__taskmgr_t *manager) { + */ + #ifdef USE_WORKER_THREADS + LOCK(&task->lock); +- push_readyq(manager, task); ++ push_readyq(manager, task, qid); + UNLOCK(&task->lock); + #else + ENQUEUE(new_ready_tasks, task, ready_link); +@@ -1297,10 +1305,14 @@ dispatch(isc__taskmgr_t *manager) { + * we're stuck. Automatically drop privileges at that + * point and continue with the regular ready queue. + */ +- if (manager->tasks_running == 0 && empty_readyq(manager)) { ++ if (manager->tasks_running == 0 && empty_readyq(manager, isc_taskqueue_normal) && empty_readyq(manager, isc_taskqueue_slow)) { + manager->mode = isc_taskmgrmode_normal; +- if (!empty_readyq(manager)) +- BROADCAST(&manager->work_available); ++ if (!empty_readyq(manager, isc_taskqueue_normal)) { ++ BROADCAST(&manager->work_available[isc_taskqueue_normal]); ++ } ++ if (!empty_readyq(manager, isc_taskqueue_slow)) { ++ BROADCAST(&manager->work_available[isc_taskqueue_slow]); ++ } + } + #endif + } +@@ -1322,13 +1334,37 @@ static isc_threadresult_t + #ifdef _WIN32 + WINAPI + #endif +-run(void *uap) { ++run_normal(void *uap) { + isc__taskmgr_t *manager = uap; + + XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_STARTING, "starting")); + +- dispatch(manager); ++ dispatch(manager, isc_taskqueue_normal); ++ ++ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ++ ISC_MSG_EXITING, "exiting")); ++ ++#ifdef OPENSSL_LEAKS ++ ERR_remove_state(0); ++#endif ++ ++ return ((isc_threadresult_t)0); ++} ++#endif /* USE_WORKER_THREADS */ ++ ++#ifdef USE_WORKER_THREADS ++static isc_threadresult_t ++#ifdef _WIN32 ++WINAPI ++#endif ++run_slow(void *uap) { ++ isc__taskmgr_t *manager = uap; ++ ++ XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ++ ISC_MSG_STARTING, "starting")); ++ ++ dispatch(manager, isc_taskqueue_slow); + + XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_EXITING, "exiting")); +@@ -1347,7 +1383,8 @@ manager_free(isc__taskmgr_t *manager) { + + #ifdef USE_WORKER_THREADS + (void)isc_condition_destroy(&manager->exclusive_granted); +- (void)isc_condition_destroy(&manager->work_available); ++ (void)isc_condition_destroy(&manager->work_available[isc_taskqueue_normal]); ++ (void)isc_condition_destroy(&manager->work_available[isc_taskqueue_slow]); + (void)isc_condition_destroy(&manager->paused); + isc_mem_free(manager->mctx, manager->threads); + #endif /* USE_WORKER_THREADS */ +@@ -1414,12 +1451,20 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + #ifdef USE_WORKER_THREADS + manager->workers = 0; + manager->threads = isc_mem_allocate(mctx, +- workers * sizeof(isc_thread_t)); ++ 2 * workers * sizeof(isc_thread_t)); + if (manager->threads == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_lock; + } +- if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) { ++ if (isc_condition_init(&manager->work_available[isc_taskqueue_normal]) != ISC_R_SUCCESS) { ++ UNEXPECTED_ERROR(__FILE__, __LINE__, ++ "isc_condition_init() %s", ++ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, ++ ISC_MSG_FAILED, "failed")); ++ result = ISC_R_UNEXPECTED; ++ goto cleanup_threads; ++ } ++ if (isc_condition_init(&manager->work_available[isc_taskqueue_slow]) != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, +@@ -1448,8 +1493,10 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + default_quantum = DEFAULT_DEFAULT_QUANTUM; + manager->default_quantum = default_quantum; + INIT_LIST(manager->tasks); +- INIT_LIST(manager->ready_tasks); +- INIT_LIST(manager->ready_priority_tasks); ++ INIT_LIST(manager->ready_tasks[isc_taskqueue_normal]); ++ INIT_LIST(manager->ready_tasks[isc_taskqueue_slow]); ++ INIT_LIST(manager->ready_priority_tasks[isc_taskqueue_normal]); ++ INIT_LIST(manager->ready_priority_tasks[isc_taskqueue_slow]); + manager->tasks_running = 0; + manager->tasks_ready = 0; + manager->exclusive_requested = false; +@@ -1465,7 +1512,19 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + * Start workers. + */ + for (i = 0; i < workers; i++) { +- if (isc_thread_create(run, manager, ++ if (isc_thread_create(run_normal, manager, ++ &manager->threads[manager->workers]) == ++ ISC_R_SUCCESS) { ++ char name[21]; /* thread name limit on Linux */ ++ snprintf(name, sizeof(name), "isc-worker%04u", i); ++ isc_thread_setname(manager->threads[manager->workers], ++ name); ++ manager->workers++; ++ started++; ++ } ++ } ++ for (; i < workers * 2; i++) { ++ if (isc_thread_create(run_slow, manager, + &manager->threads[manager->workers]) == + ISC_R_SUCCESS) { + char name[21]; /* thread name limit on Linux */ +@@ -1482,7 +1541,7 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + manager_free(manager); + return (ISC_R_NOTHREADS); + } +- isc_thread_setconcurrency(workers); ++ isc_thread_setconcurrency(workers * 2); + #endif /* USE_WORKER_THREADS */ + #ifdef USE_SHARED_MANAGER + manager->refs = 1; +@@ -1497,7 +1556,8 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + cleanup_exclusivegranted: + (void)isc_condition_destroy(&manager->exclusive_granted); + cleanup_workavailable: +- (void)isc_condition_destroy(&manager->work_available); ++ (void)isc_condition_destroy(&manager->work_available[isc_taskqueue_slow]); ++ (void)isc_condition_destroy(&manager->work_available[isc_taskqueue_normal]); + cleanup_threads: + isc_mem_free(mctx, manager->threads); + cleanup_lock: +@@ -1582,7 +1642,7 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) { + task = NEXT(task, link)) { + LOCK(&task->lock); + if (task_shutdown(task)) +- push_readyq(manager, task); ++ push_readyq(manager, task, task->qid); + UNLOCK(&task->lock); + } + #ifdef USE_WORKER_THREADS +@@ -1591,7 +1651,8 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) { + * there's work left to do, and if there are already no tasks left + * it will cause the workers to see manager->exiting. + */ +- BROADCAST(&manager->work_available); ++ BROADCAST(&manager->work_available[isc_taskqueue_normal]); ++ BROADCAST(&manager->work_available[isc_taskqueue_slow]); + UNLOCK(&manager->lock); + + /* +@@ -1693,7 +1754,8 @@ isc__taskmgr_resume(isc_taskmgr_t *manager0) { + LOCK(&manager->lock); + if (manager->pause_requested) { + manager->pause_requested = false; +- BROADCAST(&manager->work_available); ++ BROADCAST(&manager->work_available[isc_taskqueue_normal]); ++ BROADCAST(&manager->work_available[isc_taskqueue_slow]); + } + UNLOCK(&manager->lock); + } +@@ -1778,7 +1840,8 @@ isc__task_endexclusive(isc_task_t *task0) { + LOCK(&manager->lock); + REQUIRE(manager->exclusive_requested); + manager->exclusive_requested = false; +- BROADCAST(&manager->work_available); ++ BROADCAST(&manager->work_available[isc_taskqueue_normal]); ++ BROADCAST(&manager->work_available[isc_taskqueue_slow]); + UNLOCK(&manager->lock); + #else + UNUSED(task0); +@@ -1804,10 +1867,10 @@ isc__task_setprivilege(isc_task_t *task0, bool priv) { + + LOCK(&manager->lock); + if (priv && ISC_LINK_LINKED(task, ready_link)) +- ENQUEUE(manager->ready_priority_tasks, task, ++ ENQUEUE(manager->ready_priority_tasks[task->qid], task, + ready_priority_link); + else if (!priv && ISC_LINK_LINKED(task, ready_priority_link)) +- DEQUEUE(manager->ready_priority_tasks, task, ++ DEQUEUE(manager->ready_priority_tasks[task->qid], task, + ready_priority_link); + UNLOCK(&manager->lock); + } +-- +2.43.2 + diff --git a/bind.spec b/bind.spec index 16f7018..03bf065 100644 --- a/bind.spec +++ b/bind.spec @@ -181,6 +181,8 @@ Patch199: bind-9.11-stale-cache.patch Patch200: bind-9.16-update-b.root-servers.net.patch # https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/8768 Patch201: bind-9.11-CVE-2023-4408.patch +# https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/8769 +Patch202: bind-9.11-CVE-2023-50387.patch # SDB patches Patch11: bind-9.3.2b2-sdbsrc.patch @@ -592,6 +594,7 @@ are used for building ISC DHCP. %patch199 -p1 -b .RHEL-11785 %patch200 -p1 -b .b.root-servers.net %patch201 -p1 -b .CVE-2023-4408 +%patch202 -p1 -b .CVE-2023-50387+50868 mkdir lib/dns/tests/testdata/dstrandom cp -a %{SOURCE50} lib/dns/tests/testdata/dstrandom/random.data @@ -1646,6 +1649,7 @@ rm -rf ${RPM_BUILD_ROOT} %changelog * Mon Feb 26 2024 Petr Menšík - 32:9.11.36-14 - Speed up parsing of DNS messages with many different names (CVE-2023-4408) +- Prevent increased CPU consumption in DNSSEC validator (CVE-2023-50387 CVE-2023-50868) * Thu Dec 07 2023 Petr Menšík - 32:9.11.36-13 - Update addresses of b.root-servers.net (RHEL-18449)