From 4b222f154bc3d5d6755cf7089948bd4522ddb7af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
Date: Thu, 19 Jan 2023 09:14:53 +0100
Subject: [PATCH] Detach the zone views outside of the zone lock

Detaching the views in the zone_shutdown() could lead to
lock-order-inversion between adb->namelocks[bucket], adb->lock,
view->lock and zone->lock.  Detach the views outside of the section that
zone-locked.

Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/4b222f154bc3d5d6755cf7089948bd4522ddb7af

(cherry picked from commit 978a0ef84cfb08435c1b7664c6328521b743fb02)
---
 lib/dns/zone.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 9b025cdcaf..1763dbc306 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -14922,6 +14922,7 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
 	dns_zone_t *zone = (dns_zone_t *)event->ev_arg;
 	bool free_needed, linked = false;
 	dns_zone_t *raw = NULL, *secure = NULL;
+	dns_view_t *view = NULL, *prev_view = NULL;
 
 	UNUSED(task);
 	REQUIRE(DNS_ZONE_VALID(zone));
@@ -14968,13 +14969,15 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
 	LOCK_ZONE(zone);
 	INSIST(zone != zone->raw);
 
-	/* Detach the views early, we don't need them anymore */
-	if (zone->view != NULL) {
-		dns_view_weakdetach(&zone->view);
-	}
-	if (zone->prev_view != NULL) {
-		dns_view_weakdetach(&zone->prev_view);
-	}
+	/*
+	 * Detach the views early, we don't need them anymore.  However, we need
+	 * to detach them outside of the zone lock to break the lock loop
+	 * between view, adb and zone locks.
+	 */
+	view = zone->view;
+	zone->view = NULL;
+	prev_view = zone->prev_view;
+	zone->prev_view = NULL;
 
 	if (linked) {
 		isc_refcount_decrement(&zone->irefs);
@@ -15036,6 +15039,14 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
 		zone->secure = NULL;
 	}
 	UNLOCK_ZONE(zone);
+
+	if (view != NULL) {
+		dns_view_weakdetach(&view);
+	}
+	if (prev_view != NULL) {
+		dns_view_weakdetach(&prev_view);
+	}
+
 	if (raw != NULL) {
 		dns_zone_detach(&raw);
 	}
-- 
2.23.0
