diff options
Diffstat (limited to 'debian/patches/0041-CVE-2023-50387-CVE-2023-50868.patch')
-rw-r--r-- | debian/patches/0041-CVE-2023-50387-CVE-2023-50868.patch | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/debian/patches/0041-CVE-2023-50387-CVE-2023-50868.patch b/debian/patches/0041-CVE-2023-50387-CVE-2023-50868.patch new file mode 100644 index 0000000..f45dcf7 --- /dev/null +++ b/debian/patches/0041-CVE-2023-50387-CVE-2023-50868.patch @@ -0,0 +1,724 @@ +Index: bind9-git/lib/dns/dst_api.c +=================================================================== +--- bind9-git.orig/lib/dns/dst_api.c ++++ bind9-git/lib/dns/dst_api.c +@@ -105,6 +105,7 @@ static isc_result_t frombuffer(dns_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); +@@ -740,6 +741,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; +@@ -768,7 +776,7 @@ dst_key_fromdns(dns_name_t *name, dns_rd + } + + 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; +@@ -790,7 +798,7 @@ dst_key_frombuffer(dns_name_t *name, uns + REQUIRE(dst_initialized); + + result = frombuffer(name, alg, flags, protocol, rdclass, source, +- mctx, &key); ++ mctx, false, &key); + if (result != ISC_R_SUCCESS) + return (result); + +@@ -1888,7 +1896,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; +@@ -1913,10 +1922,12 @@ frombuffer(dns_name_t *name, unsigned in + 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); ++ } + } + } + +Index: bind9-git/lib/dns/include/dns/validator.h +=================================================================== +--- bind9-git.orig/lib/dns/include/dns/validator.h ++++ bind9-git/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; + }; + +Index: bind9-git/lib/dns/include/dst/dst.h +=================================================================== +--- bind9-git.orig/lib/dns/include/dst/dst.h ++++ bind9-git/lib/dns/include/dst/dst.h +@@ -417,6 +417,10 @@ dst_key_tofile(const dst_key_t *key, int + */ + + 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); + /*%< +Index: bind9-git/lib/dns/resolver.c +=================================================================== +--- bind9-git.orig/lib/dns/resolver.c ++++ bind9-git/lib/dns/resolver.c +@@ -9075,7 +9075,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; +Index: bind9-git/lib/dns/validator.c +=================================================================== +--- bind9-git.orig/lib/dns/validator.c ++++ bind9-git/lib/dns/validator.c +@@ -1200,6 +1200,12 @@ create_validator(dns_validator_t *val, d + * 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, +@@ -1209,56 +1215,58 @@ get_dst_key(dns_validator_t *val, dns_rd + 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) +- goto failure; ++ goto done; + 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) == true) +- { +- 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); + } 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); + } + +@@ -1626,37 +1634,13 @@ validate(dns_validator_t *val, bool resu + 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, +@@ -1693,9 +1677,13 @@ validate(dns_validator_t *val, bool resu + } 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), +Index: bind9-git/lib/dns/win32/libdns.def.in +=================================================================== +--- bind9-git.orig/lib/dns/win32/libdns.def.in ++++ bind9-git/lib/dns/win32/libdns.def.in +@@ -1435,6 +1435,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 +Index: bind9-git/lib/isc/include/isc/task.h +=================================================================== +--- bind9-git.orig/lib/isc/include/isc/task.h ++++ bind9-git/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 */ +Index: bind9-git/lib/isc/task.c +=================================================================== +--- bind9-git.orig/lib/isc/task.c ++++ bind9-git/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); +@@ -362,7 +364,13 @@ isc__task_create(isc_taskmgr_t *manager0 + 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); +@@ -473,10 +481,12 @@ task_ready(isc__task_t *task) { + XTRACE("task_ready"); + + LOCK(&manager->lock); +- push_readyq(manager, task); ++ LOCK(&task->lock); ++ 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); + } +@@ -947,13 +957,13 @@ isc__task_getcurrenttimex(isc_task_t *ta + * 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)); + } +@@ -967,18 +977,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); + } + +@@ -992,16 +1002,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; +@@ -1080,26 +1090,26 @@ 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")); + } + #else /* USE_WORKER_THREADS */ + if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM || +- empty_readyq(manager)) ++ empty_readyq(manager, qid)) + break; + #endif /* USE_WORKER_THREADS */ + 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; +@@ -1263,7 +1273,9 @@ dispatch(isc__taskmgr_t *manager) { + * might even hurt rather than help. + */ + #ifdef USE_WORKER_THREADS +- push_readyq(manager, task); ++ LOCK(&task->lock); ++ push_readyq(manager, task, qid); ++ UNLOCK(&task->lock); + #else + ENQUEUE(new_ready_tasks, task, ready_link); + if ((task->flags & TASK_F_PRIVILEGED) != 0) +@@ -1281,20 +1293,24 @@ 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 + } + + #ifndef USE_WORKER_THREADS +- ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link); +- ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks, ++ ISC_LIST_APPENDLIST(manager->ready_tasks[qid], new_ready_tasks, ready_link); ++ ISC_LIST_APPENDLIST(manager->ready_priority_tasks[qid], new_priority_tasks, + ready_priority_link); + manager->tasks_ready += tasks_ready; +- if (empty_readyq(manager)) ++ if (empty_readyq(manager, qid)) + manager->mode = isc_taskmgrmode_normal; + #endif + +@@ -1306,13 +1322,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")); +@@ -1331,7 +1371,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 */ +@@ -1398,12 +1439,20 @@ isc__taskmgr_create(isc_mem_t *mctx, uns + #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, +@@ -1432,8 +1481,10 @@ isc__taskmgr_create(isc_mem_t *mctx, uns + 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; +@@ -1449,10 +1500,22 @@ isc__taskmgr_create(isc_mem_t *mctx, uns + * 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[16]; /* thread name limit on Linux */ ++ char name[21]; /* thread name limit on Linux */ + snprintf(name, sizeof(name), "isc-worker%04u", i); + isc_thread_setname(manager->threads[manager->workers], + name); +@@ -1466,7 +1529,7 @@ isc__taskmgr_create(isc_mem_t *mctx, uns + 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; +@@ -1481,7 +1544,8 @@ isc__taskmgr_create(isc_mem_t *mctx, uns + 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: +@@ -1566,7 +1630,7 @@ isc__taskmgr_destroy(isc_taskmgr_t **man + 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 +@@ -1575,7 +1639,8 @@ isc__taskmgr_destroy(isc_taskmgr_t **man + * 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); + + /* +@@ -1636,7 +1701,8 @@ isc__taskmgr_ready(isc_taskmgr_t *manage + return (false); + + LOCK(&manager->lock); +- is_ready = !empty_readyq(manager); ++ is_ready = !empty_readyq(manager, isc_taskqueue_normal) || ++ !empty_readyq(manager, isc_taskqueue_slow); + UNLOCK(&manager->lock); + + return (is_ready); +@@ -1653,7 +1719,8 @@ isc__taskmgr_dispatch(isc_taskmgr_t *man + if (manager == NULL) + return (ISC_R_NOTFOUND); + +- dispatch(manager); ++ dispatch(manager, isc_taskqueue_normal); ++ dispatch(manager, isc_taskqueue_slow); + + return (ISC_R_SUCCESS); + } +@@ -1677,7 +1744,8 @@ isc__taskmgr_resume(isc_taskmgr_t *manag + 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); + } +@@ -1753,7 +1821,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); +@@ -1779,10 +1848,10 @@ isc__task_setprivilege(isc_task_t *task0 + + 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); + } |