From dd73306509b4703011cbc6a8cc3d3667a58110d3 Mon Sep 17 00:00:00 2001
From: Mark Andrews <marka@isc.org>
Date: Wed, 30 Nov 2022 18:44:37 +1100
Subject: [PATCH] Call dns_db_updatenotify_unregister earlier

dns_db_updatenotify_unregister needed to be called earlier to ensure
that listener->onupdate_arg always points to a valid object.  The
existing lazy cleanup in rbtdb_free did not ensure that.

(cherry picked from commit 35839e91d84f4c22f3554ff4b6dc53d20359621e)
---
 lib/dns/include/dns/zone.h |  3 +-
 lib/dns/rbtdb.c            | 10 +------
 lib/dns/zone.c             | 60 ++++++++++++++++++++++----------------
 3 files changed, 38 insertions(+), 35 deletions(-)

diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index cb5da5d046e..4bdc936949a 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -2610,7 +2610,8 @@ dns_zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs);
 void
 dns_zone_catz_disable(dns_zone_t *zone);
 /*%<
- * Disable zone as catalog zone, if it is one.
+ * Disable zone as catalog zone, if it is one.  Also disables any
+ * registered callbacks for the catalog zone.
  *
  * Requires:
  *
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index 36fce510244..b36cdf22059 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -1063,7 +1063,6 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) {
 	char buf[DNS_NAME_FORMATSIZE];
 	dns_rbt_t **treep;
 	isc_time_t start;
-	dns_dbonupdatelistener_t *listener, *listener_next;
 
 	if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) {
 		overmem((dns_db_t *)rbtdb, (bool)-1);
@@ -1220,14 +1219,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) {
 		isc_file_munmap(rbtdb->mmap_location, (size_t)rbtdb->mmap_size);
 	}
 
-	for (listener = ISC_LIST_HEAD(rbtdb->common.update_listeners);
-	     listener != NULL; listener = listener_next)
-	{
-		listener_next = ISC_LIST_NEXT(listener, link);
-		ISC_LIST_UNLINK(rbtdb->common.update_listeners, listener, link);
-		isc_mem_put(rbtdb->common.mctx, listener,
-			    sizeof(dns_dbonupdatelistener_t));
-	}
+	INSIST(ISC_LIST_EMPTY(rbtdb->common.update_listeners));
 
 	isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
 }
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 62c102b374f..21e71767e93 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -1938,6 +1938,31 @@ dns_zone_rpz_disable_db(dns_zone_t *zone, dns_db_t *db) {
 					     zone->rpzs->zones[zone->rpz_num]);
 }
 
+/*
+ * If a zone is a catalog zone, attach it to update notification in database.
+ */
+void
+dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db) {
+	REQUIRE(DNS_ZONE_VALID(zone));
+	REQUIRE(db != NULL);
+
+	if (zone->catzs != NULL) {
+		dns_db_updatenotify_register(db, dns_catz_dbupdate_callback,
+					     zone->catzs);
+	}
+}
+
+static void
+dns_zone_catz_disable_db(dns_zone_t *zone, dns_db_t *db) {
+	REQUIRE(DNS_ZONE_VALID(zone));
+	REQUIRE(db != NULL);
+
+	if (zone->catzs != NULL) {
+		dns_db_updatenotify_unregister(db, dns_catz_dbupdate_callback,
+					       zone->catzs);
+	}
+}
+
 static void
 zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs) {
 	REQUIRE(DNS_ZONE_VALID(zone));
@@ -1964,6 +1989,9 @@ zone_catz_disable(dns_zone_t *zone) {
 	REQUIRE(DNS_ZONE_VALID(zone));
 
 	if (zone->catzs != NULL) {
+		if (zone->db != NULL) {
+			dns_zone_catz_disable_db(zone, zone->db);
+		}
 		dns_catz_catzs_detach(&zone->catzs);
 	}
 }
@@ -1984,31 +2012,6 @@ dns_zone_catz_is_enabled(dns_zone_t *zone) {
 	return (zone->catzs != NULL);
 }
 
-/*
- * If a zone is a catalog zone, attach it to update notification in database.
- */
-void
-dns_zone_catz_enable_db(dns_zone_t *zone, dns_db_t *db) {
-	REQUIRE(DNS_ZONE_VALID(zone));
-	REQUIRE(db != NULL);
-
-	if (zone->catzs != NULL) {
-		dns_db_updatenotify_register(db, dns_catz_dbupdate_callback,
-					     zone->catzs);
-	}
-}
-
-static void
-dns_zone_catz_disable_db(dns_zone_t *zone, dns_db_t *db) {
-	REQUIRE(DNS_ZONE_VALID(zone));
-	REQUIRE(db != NULL);
-
-	if (zone->catzs != NULL) {
-		dns_db_updatenotify_unregister(db, dns_catz_dbupdate_callback,
-					       zone->catzs);
-	}
-}
-
 /*
  * Set catalog zone ownership of the zone
  */
@@ -5375,6 +5378,11 @@ cleanup:
 			   isc_result_totext(result));
 	}
 
+	if (result != ISC_R_SUCCESS) {
+		dns_zone_rpz_disable_db(zone, db);
+		dns_zone_catz_disable_db(zone, db);
+	}
+
 	for (inc = ISC_LIST_HEAD(zone->newincludes); inc != NULL;
 	     inc = ISC_LIST_HEAD(zone->newincludes))
 	{
@@ -17472,6 +17480,8 @@ static void
 zone_detachdb(dns_zone_t *zone) {
 	REQUIRE(zone->db != NULL);
 
+	dns_zone_rpz_disable_db(zone, zone->db);
+	dns_zone_catz_disable_db(zone, zone->db);
 	dns_db_detach(&zone->db);
 }
 
-- 
2.23.0