From 2a3b6d1406ab6b68849e1a9d753707a169ac8b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 18 Dec 2023 11:33:43 +0100 Subject: [PATCH] Fix reference counting in do_nsfetch() Each function queuing a do_nsfetch() call using isc_async_run() is expected to increase the given zone's internal reference count (zone->irefs), which is then correspondingly decreased in either do_nsfetch() itself (when the dns_resolver_createfetch() fails) or in nsfetch_done() (when recursion is finished). However, do_nsfetch() can also return early if either the zone itself or the relevant view's resolver object is being shut down. In that case, do_nsfetch() simply returns without decreasing the internal reference count for the zone. This leaves a dangling zone reference around, which leads to hangs during named shutdown. Fix by executing the same cleanup code for early returns from do_nsfetch() as for a failed dns_resolver_createfetch() call in that function as the reference count will not be decreased in nsfetch_done() in any of these cases. --- lib/dns/zone.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9f54bc6ddb..28e6226462 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -21049,12 +21049,13 @@ do_nsfetch(void *arg) { unsigned int options = DNS_FETCHOPT_UNSHARED | DNS_FETCHOPT_NOCACHED; if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { - return; + result = ISC_R_SHUTTINGDOWN; + goto cleanup; } result = dns_view_getresolver(zone->view, &resolver); if (result != ISC_R_SUCCESS) { - return; + goto cleanup; } if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) { @@ -21085,6 +21086,7 @@ do_nsfetch(void *arg) { dns_resolver_detach(&resolver); +cleanup: if (result != ISC_R_SUCCESS) { dns_name_t *zname = dns_fixedname_name(&nsfetch->name); bool free_needed;