From fc24cfd71d4260325cd16c3a47f6027347229ced Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Tue, 11 Feb 2025 10:22:35 +0000 Subject: [PATCH] Fix a race issue in dns_view_addzone() Views use two types of reference counting - regular and weak, and when there are no more regular references, the view_flushanddetach() function destroys or detaches some parts of the view, including 'view->zonetable', while other parts are freed by destroy() when the last weak reference is detached. Since catalog zones use weak references to attach a view, it's currently possible that during shutdown catalog zone processing will try to add a new zone into an otherwise unused view (because it's shutting down) which doesn't have an attached zonetable any more. This could cause an assertion failure. Fix this issue by modifying the dns_view_addzone() function to expect that 'view->zonetable' can be NULL, and in that case just return ISC_R_SHUTTINGDOWN. --- lib/dns/include/dns/view.h | 6 ++++++ lib/dns/view.c | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index b7a4798703..df46400d2e 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -524,6 +524,12 @@ dns_view_addzone(dns_view_t *view, dns_zone_t *zone); *\li 'view' is a valid, unfrozen view. * *\li 'zone' is a valid zone. + * + * Returns: + * + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_SHUTTINGDOWN Shutting down + *\li Other values returned by dns_zt_mount() */ void diff --git a/lib/dns/view.c b/lib/dns/view.c index 8f23d8a155..7c88fa8501 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -1010,13 +1010,22 @@ dns_view_thaw(dns_view_t *view) { isc_result_t dns_view_addzone(dns_view_t *view, dns_zone_t *zone) { - isc_result_t result; + isc_result_t result = ISC_R_SHUTTINGDOWN; + dns_zt_t *zt = NULL; REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(!view->frozen); - REQUIRE(view->zonetable != NULL); - result = dns_zt_mount(view->zonetable, zone); + LOCK(&view->lock); + if (view->zonetable != NULL) { + dns_zt_attach(view->zonetable, &zt); + } + UNLOCK(&view->lock); + + if (zt != NULL) { + result = dns_zt_mount(zt, zone); + dns_zt_detach(&zt); + } return result; }