Skip to content

Commit

Permalink
Merge branch 'ondrej/split-taskmgr-9.16' into 'v9.16.47-release'
Browse files Browse the repository at this point in the history
[9.16] [CVE-2023-50387] Fix KeyTrap

See merge request isc-private/bind9!629
  • Loading branch information
kempniu committed Feb 1, 2024
2 parents a0c78d1 + 0ab4125 commit 435787e
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 68 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
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]

6321. [security] Change 6315 inadvertently introduced regressions that
could cause named to crash. [GL #4234]

Expand Down
31 changes: 31 additions & 0 deletions doc/notes/notes-current.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
..
.. SPDX-License-Identifier: MPL-2.0
..
.. This Source Code Form is subject to the terms of the Mozilla Public
.. License, v. 2.0. If a copy of the MPL was not distributed with this
.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
..
.. See the COPYRIGHT file distributed with this work for additional
.. information regarding copyright ownership.
Notes for BIND 9.16.47
----------------------

Security Fixes
~~~~~~~~~~~~~~

- Validating DNS messages containing a lot of DNSSEC signatures could
cause excessive CPU load, leading to a denial-of-service condition.
This has been fixed. :cve:`2023-50387`

ISC would like to thank Elias Heftrig, Haya Schulmann, Niklas Vogel,
and Michael Waidner from the German National Research Center for
Applied Cybersecurity ATHENE. :gl:`#4424`

Known Issues
~~~~~~~~~~~~

- There are no new known issues with this release. See :ref:`above
<relnotes_known_issues>` for a list of all known issues affecting this
BIND 9 branch.
27 changes: 19 additions & 8 deletions lib/dns/dst_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,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);
Expand Down Expand Up @@ -780,6 +781,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;
Expand Down Expand Up @@ -810,7 +818,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);
}
Expand All @@ -831,7 +839,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);
}
Expand Down Expand Up @@ -2337,7 +2345,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;

Expand All @@ -2362,10 +2371,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);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/dns/include/dns/validator.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ struct dns_validator {
unsigned int depth;
unsigned int authcount;
unsigned int authfail;
bool failed;
isc_stdtime_t start;
};

Expand Down
4 changes: 4 additions & 0 deletions lib/dns/include/dst/dst.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,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);
/*%<
Expand Down
4 changes: 2 additions & 2 deletions lib/dns/resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -10634,8 +10634,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;
Expand Down
67 changes: 30 additions & 37 deletions lib/dns/validator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1104,8 +1104,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,
Expand All @@ -1118,59 +1118,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);
}

Expand Down Expand Up @@ -1589,20 +1589,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 {
Expand Down Expand Up @@ -1639,9 +1628,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),
Expand Down
3 changes: 3 additions & 0 deletions lib/isc/include/isc/netmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,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);
/*%<
Expand Down
1 change: 1 addition & 0 deletions lib/isc/netmgr/netmgr-int.h
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,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;
Expand Down
36 changes: 23 additions & 13 deletions lib/isc/netmgr/netmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,12 @@ 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);
}
}
Expand All @@ -254,11 +254,11 @@ isc__nm_threadpool_initialize(uint32_t workers) {
#endif

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 MAXIMAL_UV_VERSION
if (uv_version() > MAXIMAL_UV_VERSION) {
Expand All @@ -282,10 +282,13 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
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);
Expand Down Expand Up @@ -316,11 +319,12 @@ isc__netmgr_create(isc_mem_t *mctx, uint32_t workers, isc_nm_t **netmgrp) {
atomic_init(&mgr->keepalive, 30000);
atomic_init(&mgr->advertised, 30000);

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++) {
isc__networker_t *worker = &mgr->workers[i];
int r;

Expand Down Expand Up @@ -354,7 +358,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);
}

Expand Down Expand Up @@ -840,9 +844,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];
Expand Down

0 comments on commit 435787e

Please sign in to comment.