]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix deadlock in RPZ update code.
authorWitold Kręcicki <wpk@isc.org>
Thu, 4 Apr 2019 20:05:25 +0000 (22:05 +0200)
committerEvan Hunt <each@isc.org>
Sat, 6 Apr 2019 19:41:36 +0000 (12:41 -0700)
In dns_rpz_update_from_db we call setup_update which creates the db
iterator and calls dns_dbiterator_first. This unpauses the iterator and
might cause db->tree_lock to be acquired. We then do isc_task_send(...)
on an event to do quantum_update, which (correctly) after each iteration
calls dns_dbiterator_pause, and re-isc_task_sends itself.

That's an obvious bug, as we're holding a lock over an async task send -
if a task requesting write (e.g. prune_tree) is scheduled on the same
workers queue as update_quantum but before it, it will wait for the
write lock indefinitely, resulting in a deadlock.

To fix it we have to pause dbiterator in setup_update.

(cherry picked from commit 06021b3529e32f3ada6333222100ea34c52f58eb)

CHANGES
lib/dns/rpz.c

diff --git a/CHANGES b/CHANGES
index 1d067b5e9c774b6f3a7cdff55a76371a2984b3b5..2fd7265a88e7a1e98ed3d2a90e9cb01b062a7c92 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+5201.  [bug]           Fix a possible deadlock in RPZ update code. [GL #973]
+
 5198.  [bug]           If a fetch context was being shut down and, at the same
                        time, we returned from qname minimization, an INSIST
                        could be hit. [GL #966]
index e6e2f3ab42140a7a6ce5fdb330942f60bab67eb0..d39692d2152de712ee1b644c2f4dc07a347cfd13 100644 (file)
@@ -1734,6 +1734,16 @@ setup_update(dns_rpz_zone_t *rpz) {
                goto cleanup;
        }
 
+       result = dns_dbiterator_pause(rpz->updbit);
+       if (result != ISC_R_SUCCESS) {
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+                             DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
+                             "rpz: %s: failed to pause db iterator - %s",
+                             domain, isc_result_totext(result));
+               goto cleanup;
+       }
+
+
  cleanup:
        if (result != ISC_R_SUCCESS) {
                if (rpz->updbit != NULL)