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)
+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]
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)