]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix a race issue in dns_view_addzone()
authorAram Sargsyan <aram@isc.org>
Tue, 11 Feb 2025 10:22:35 +0000 (10:22 +0000)
committerArаm Sаrgsyаn <aram@isc.org>
Mon, 17 Feb 2025 17:21:38 +0000 (17:21 +0000)
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
lib/dns/view.c

index b7a479870345713dfe2f9aead83a7cb21fbf7f03..df46400d2ea76f83d63966c06c0a6c8ef39c4999 100644 (file)
@@ -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
index 8f23d8a1555027c3ba9286ac27c73539a01d00d9..7c88fa8501689daf1b1bf088acfe5896e9a10e69 100644 (file)
@@ -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;
 }