From 38734d80b5ea2bf62a3bba56a42fea3e3a4a93f4 Mon Sep 17 00:00:00 2001
From: Mark Andrews <marka@isc.org>
Date: Fri, 4 Sep 2020 16:07:57 +1000
Subject: [PATCH] Pause dbiterator to release rwlock to prevent
 lock-order-inversion.

    WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
    Cycle in lock order graph: M1 (0x000000000001) => M2 (0x000000000000) => M1

    Mutex M2 acquired here while holding mutex M1 in thread T1:
    #0 pthread_rwlock_rdlock <null>
    #1 isc_rwlock_lock lib/isc/rwlock.c:48:3
    #2 zone_sign lib/dns/zone.c:9247:3
    #3 zone_maintenance lib/dns/zone.c:11047:4
    #4 zone_timer lib/dns/zone.c:14090:2
    #5 dispatch lib/isc/task.c:1152:7
    #6 run lib/isc/task.c:1344:2

    Mutex M1 previously acquired by the same thread here:
    #0 pthread_rwlock_rdlock <null>
    #1 isc_rwlock_lock lib/isc/rwlock.c:48:3
    #2 resume_iteration lib/dns/rbtdb.c:9357:2
    #3 dbiterator_next lib/dns/rbtdb.c:9647:3
    #4 dns_dbiterator_next lib/dns/dbiterator.c:87:10
    #5 zone_sign lib/dns/zone.c:9488:13
    #6 zone_maintenance lib/dns/zone.c:11047:4
    #7 zone_timer lib/dns/zone.c:14090:2
    #8 dispatch lib/isc/task.c:1152:7
    #9 run lib/isc/task.c:1344:2

    Mutex M1 acquired here while holding mutex M2 in thread T2:
    #0 pthread_rwlock_rdlock <null>
    #1 isc_rwlock_lock lib/isc/rwlock.c:48:3
    #2 findnodeintree lib/dns/rbtdb.c:2877:2
    #3 findnode lib/dns/rbtdb.c:2941:10
    #4 dns_db_findnode lib/dns/db.c:439:11
    #5 dns_db_getsoaserial lib/dns/db.c:780:11
    #6 dump_done lib/dns/zone.c:11428:15
    #7 dump_quantum lib/dns/masterdump.c:1487:2
    #8 dispatch lib/isc/task.c:1152:7
    #9 run lib/isc/task.c:1344:2

    Mutex M2 previously acquired by the same thread here:
    #0 pthread_rwlock_rdlock <null>
    #1 isc_rwlock_lock lib/isc/rwlock.c:48:3
    #2 dump_done lib/dns/zone.c:11426:4
    #3 dump_quantum lib/dns/masterdump.c:1487:2
    #4 dispatch lib/isc/task.c:1152:7
    #5 run lib/isc/task.c:1344:2

    Thread T1 (running) created by main thread at:
    #0 pthread_create <null>
    #1 isc_thread_create lib/isc/pthreads/thread.c:73:8
    #2 isc_taskmgr_create lib/isc/task.c:1434:3
    #3 create_managers bin/named/main.c:915:11
    #4 setup bin/named/main.c:1223:11
    #5 main bin/named/main.c:1523:2

    Thread T2 (running) created by main thread at:
    #0 pthread_create <null>
    #1 isc_thread_create lib/isc/pthreads/thread.c:73:8
    #2 isc_taskmgr_create lib/isc/task.c:1434:3
    #3 create_managers bin/named/main.c:915:11
    #4 setup bin/named/main.c:1223:11
    #5 main bin/named/main.c:1523:2

    SUMMARY: ThreadSanitizer: lock-order-inversion (potential deadlock) in pthread_rwlock_rdlock

(cherry picked from commit c9dbad97b2f96fcfba3290fe52f6b044af64d780)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/38734d80b5ea2bf62a3bba56a42fea3e3a4a93f4
---
 lib/dns/zone.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 55eb1d72ec..b024034e63 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -8645,6 +8645,8 @@ zone_sign(dns_zone_t *zone) {
 
 	while (signing != NULL && nodes-- > 0 && signatures > 0) {
 		bool has_alg = false;
+
+		dns_dbiterator_pause(signing->dbiterator);
 		nextsigning = ISC_LIST_NEXT(signing, link);
 
 		ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
-- 
2.23.0

