]> 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:22:49 +0000 (12:22 -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.

CHANGES
lib/dns/rpz.c

diff --git a/CHANGES b/CHANGES
index af5a8dec18d150c107039cddd6a15698de297d8d..0dadfa32eed66cae7370cec4d4decee2ed6ac0f9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+5201.  [bug]           Fix a possible deadlock in RPZ update code. [GL #973]
+
 5200.  [placeholder]
 
 5199.  [placeholder]
index 3af65e74d67e83abaaf4d443da0f64107f3016d8..5aaab10d1dc85a11eaf385eebb006118b48aa882 100644 (file)
@@ -1732,6 +1732,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)