2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

Merge branch '3643-dont-use-dns_zone_attach-in-zone_refreshkeys' into 'main'

Don't use dns_zone_attach() in zone_refreshkeys()

Closes #3643

See merge request isc-projects/bind9!7022
This commit is contained in:
Ondřej Surý
2022-11-03 13:53:07 +00:00

View File

@@ -812,6 +812,7 @@ struct dns_keymgmt {
*/
struct dns_keyfetch {
isc_mem_t *mctx;
dns_fixedname_t name;
dns_rdataset_t keydataset;
dns_rdataset_t dnskeyset;
@@ -5797,8 +5798,11 @@ dns_zone_detach(dns_zone_t **zonep) {
isc_refcount_destroy(&zone->erefs);
/*
* We just detached the last external reference.
* Stop things being restarted after we cancel them below.
*/
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING);
dns_zone_log(zone, ISC_LOG_INFO, "final reference detached");
if (zone->loop != NULL) {
/*
* This zone has a loop; it can clean
@@ -5810,24 +5814,18 @@ dns_zone_detach(dns_zone_t **zonep) {
/*
* This zone is unmanaged; we're probably running in
* named-checkzone or a unit test. There's no loop, so we need
* to free it immediately.
* named-checkzone or a unit test. There's no loop, so we
* need to free it immediately.
*
* Unmanaged zones must not have null views;
* we have no way of detaching from the view here
* without causing deadlock because this code is
* called with the view already locked.
* Unmanaged zones must not have null views; we have no way
* of detaching from the view here without causing deadlock
* because this code is called with the view already
* locked.
*/
INSIST(isc_tid() == ISC_TID_UNKNOWN);
INSIST(zone->view == NULL);
if (zone->raw != NULL) {
dns_zone_detach(&zone->raw);
}
if (zone->secure != NULL) {
dns_zone_idetach(&zone->secure);
}
zone_free(zone);
zone_shutdown(zone);
}
}
@@ -5872,7 +5870,6 @@ zone_idetach(dns_zone_t **zonep) {
void
dns_zone_idetach(dns_zone_t **zonep) {
dns_zone_t *zone;
bool free_needed;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
@@ -5880,6 +5877,7 @@ dns_zone_idetach(dns_zone_t **zonep) {
*zonep = NULL;
if (isc_refcount_decrement(&zone->irefs) == 1) {
bool free_needed;
LOCK_ZONE(zone);
free_needed = exit_check(zone);
UNLOCK_ZONE(zone);
@@ -10552,7 +10550,7 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
kfetch = event->ev_arg;
zone = kfetch->zone;
isc_mem_attach(zone->mctx, &mctx);
mctx = kfetch->mctx;
keyname = dns_fixedname_name(&kfetch->name);
dnskeys = &kfetch->dnskeyset;
dnskeysigs = &kfetch->dnskeysigset;
@@ -11145,11 +11143,9 @@ failure:
cleanup:
dns_db_detach(&kfetch->db);
isc_refcount_decrement(&zone->irefs);
/* The zone must be managed */
INSIST(kfetch->zone->loop != NULL);
dns_zone_detach(&kfetch->zone);
isc_refcount_decrement(&zone->irefs);
if (dns_rdataset_isassociated(keydataset)) {
dns_rdataset_disassociate(keydataset);
@@ -11162,7 +11158,7 @@ cleanup:
}
dns_name_free(keyname, mctx);
isc_mem_putanddetach(&mctx, kfetch, sizeof(dns_keyfetch_t));
isc_mem_putanddetach(&kfetch->mctx, kfetch, sizeof(dns_keyfetch_t));
if (secroots != NULL) {
dns_keytable_detach(&secroots);
@@ -11181,30 +11177,42 @@ cleanup:
static void
retry_keyfetch(dns_keyfetch_t *kfetch, dns_name_t *kname) {
isc_time_t timenow, timethen;
char timebuf[80];
dns_zone_t *zone = kfetch->zone;
bool free_needed;
/*
* Error during a key fetch; cancel and retry in an hour.
*/
LOCK_ZONE(zone);
zone->refreshkeycount--;
isc_refcount_decrement(&zone->irefs);
dns_db_detach(&kfetch->db);
dns_rdataset_disassociate(&kfetch->keydataset);
dns_name_free(kname, zone->mctx);
isc_mem_put(zone->mctx, kfetch, sizeof(dns_keyfetch_t));
isc_mem_putanddetach(&kfetch->mctx, kfetch, sizeof(*kfetch));
dnssec_log(zone, ISC_LOG_WARNING,
"Failed to create fetch for DNSKEY update");
TIME_NOW(&timenow);
DNS_ZONE_TIME_ADD(&timenow, dns_zone_mkey_hour, &timethen);
zone->refreshkeytime = timethen;
zone_settimer(zone, &timenow);
if (!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
/* Don't really retry if we are exiting */
char timebuf[80];
isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
dnssec_log(zone, ISC_LOG_DEBUG(1), "retry key refresh: %s", timebuf);
TIME_NOW(&timenow);
DNS_ZONE_TIME_ADD(&timenow, dns_zone_mkey_hour, &timethen);
zone->refreshkeytime = timethen;
zone_settimer(zone, &timenow);
dns_zone_detach(&zone);
isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
dnssec_log(zone, ISC_LOG_DEBUG(1), "retry key refresh: %s",
timebuf);
}
free_needed = exit_check(zone);
UNLOCK_ZONE(zone);
if (free_needed) {
zone_free(zone);
}
}
static void
@@ -11217,11 +11225,24 @@ do_keyfetch(void *arg) {
unsigned int options = DNS_FETCHOPT_NOVALIDATE | DNS_FETCHOPT_UNSHARED |
DNS_FETCHOPT_NOCACHED;
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
goto retry;
}
result = dns_view_getresolver(zone->view, &resolver);
if (result != ISC_R_SUCCESS) {
goto retry;
}
/*
* Use of DNS_FETCHOPT_NOCACHED is essential here. If it is not
* set and the cache still holds a non-expired, validated version
* of the RRset being queried for by the time the response is
* received, the cached RRset will be passed to keyfetch_done()
* instead of the one received in the response as the latter will
* have a lower trust level due to not being validated until
* keyfetch_done() is called.
*/
result = dns_resolver_createfetch(
resolver, kname, dns_rdatatype_dnskey, NULL, NULL, NULL, NULL,
0, options, 0, NULL, zone->task, keyfetch_done, kfetch,
@@ -11284,7 +11305,6 @@ zone_refreshkeys(dns_zone_t *zone) {
isc_stdtime_t timer = 0xffffffff;
dns_name_t *name = NULL, *kname = NULL;
dns_rdataset_t *kdset = NULL;
dns_keyfetch_t *kfetch;
uint32_t ttl;
dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
@@ -11336,55 +11356,39 @@ zone_refreshkeys(dns_zone_t *zone) {
dns_rriterator_pause(&rrit);
kfetch = isc_mem_get(zone->mctx, sizeof(dns_keyfetch_t));
*kfetch = (dns_keyfetch_t){ .zone = NULL };
zone->refreshkeycount++;
dns_zone_attach(zone, &kfetch->zone);
isc_refcount_increment0(&zone->irefs);
kname = dns_fixedname_initname(&kfetch->name);
dns_name_dup(name, zone->mctx, kname);
dns_rdataset_init(&kfetch->dnskeyset);
dns_rdataset_init(&kfetch->dnskeysigset);
dns_rdataset_init(&kfetch->keydataset);
dns_rdataset_clone(kdset, &kfetch->keydataset);
kfetch->db = NULL;
dns_db_attach(db, &kfetch->db);
kfetch->fetch = NULL;
if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(kname, namebuf, sizeof(namebuf));
dnssec_log(zone, ISC_LOG_DEBUG(3),
"Creating key fetch in "
"zone_refreshkeys() for '%s'",
namebuf);
}
/*
* Use of DNS_FETCHOPT_NOCACHED is essential here. If it is
* not set and the cache still holds a non-expired, validated
* version of the RRset being queried for by the time the
* response is received, the cached RRset will be passed to
* keyfetch_done() instead of the one received in the response
* as the latter will have a lower trust level due to not being
* validated until keyfetch_done() is called.
*/
#ifdef ENABLE_AFL
if (!dns_fuzzing_resolver) {
#endif /* ifdef ENABLE_AFL */
dns_keyfetch_t *kfetch = NULL;
kfetch = isc_mem_get(zone->mctx,
sizeof(dns_keyfetch_t));
*kfetch = (dns_keyfetch_t){ .zone = zone };
isc_mem_attach(zone->mctx, &kfetch->mctx);
zone->refreshkeycount++;
isc_refcount_increment0(&zone->irefs);
kname = dns_fixedname_initname(&kfetch->name);
dns_name_dup(name, zone->mctx, kname);
dns_rdataset_init(&kfetch->dnskeyset);
dns_rdataset_init(&kfetch->dnskeysigset);
dns_rdataset_init(&kfetch->keydataset);
dns_rdataset_clone(kdset, &kfetch->keydataset);
dns_db_attach(db, &kfetch->db);
if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(kname, namebuf,
sizeof(namebuf));
dnssec_log(zone, ISC_LOG_DEBUG(3),
"Creating key fetch in "
"zone_refreshkeys() for '%s'",
namebuf);
}
isc_async_run(zone->loop, do_keyfetch, kfetch);
fetching = true;
#ifdef ENABLE_AFL
} else {
zone->refreshkeycount--;
isc_refcount_decrement(&zone->irefs);
dns_db_detach(&kfetch->db);
dns_rdataset_disassociate(&kfetch->keydataset);
dns_name_free(kname, zone->mctx);
dns_zone_detach(&kfetch->zone);
isc_mem_put(zone->mctx, kfetch, sizeof(dns_keyfetch_t));
}
#endif /* ifdef ENABLE_AFL */
}
@@ -11422,34 +11426,24 @@ static void
zone_maintenance(dns_zone_t *zone) {
isc_time_t now;
isc_result_t result;
bool dumping, load_pending, viewok, notify, refreshkeys;
bool sign, resign, rekey, chain, warn_expire;
bool load_pending, exiting, dumping, viewok, notify;
bool refreshkeys, sign, resign, rekey, chain, warn_expire;
REQUIRE(DNS_ZONE_VALID(zone));
ENTER;
/*
* Are we pending load/reload?
* Are we pending load/reload, exiting, or unconfigured
* (e.g. because of a syntax failure in the config file)?
* If so, don't attempt maintenance.
*/
LOCK_ZONE(zone);
load_pending = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING);
UNLOCK_ZONE(zone);
if (load_pending) {
return;
}
/*
* Configuring the view of this zone may have
* failed, for example because the config file
* had a syntax error. In that case, the view
* adb or resolver will be NULL, and we had better not try
* to do further maintenance on it.
*/
LOCK_ZONE(zone);
exiting = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING);
viewok = (zone->view != NULL && zone->view->adb != NULL);
UNLOCK_ZONE(zone);
if (!viewok) {
if (load_pending || exiting || !viewok) {
return;
}
@@ -15117,8 +15111,7 @@ unlock:
}
/*
* Handle the control event. Note that although this event causes the zone
* to shut down, it is not a shutdown event in the sense of the task library.
* Shut the zone down.
*/
static void
zone_shutdown(void *arg) {
@@ -15131,13 +15124,6 @@ zone_shutdown(void *arg) {
zone_debuglog(zone, __func__, 3, "shutting down");
/*
* Stop things being restarted after we cancel them below.
*/
LOCK_ZONE(zone);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING);
UNLOCK_ZONE(zone);
/*
* If we were waiting for xfrin quota, step out of
* the queue.
@@ -15285,7 +15271,6 @@ zone_timer_set(dns_zone_t *zone, isc_time_t *next, isc_time_t *now) {
static void
zone__settimer(void *arg) {
zone_settimer_t *data = arg;
dns_zone_t *zone = data->zone;
isc_time_t *now = &data->now;
isc_time_t next;
@@ -15443,6 +15428,10 @@ free:
static void
zone_settimer(dns_zone_t *zone, isc_time_t *now) {
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) {
return;
}
zone_settimer_t *arg = isc_mem_get(zone->mctx, sizeof(*arg));
*arg = (zone_settimer_t){
.zone = zone,