]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Gracefully handle resending a node to prune_tree()
authorMichał Kępień <michal@isc.org>
Thu, 29 Feb 2024 16:38:52 +0000 (17:38 +0100)
committerMichał Kępień <michal@isc.org>
Thu, 29 Feb 2024 17:06:12 +0000 (18:06 +0100)
Commit 801e888d03e0ae34c5ecf00385defa77844f4023 made the prune_tree()
function use send_to_prune_tree() for triggering pruning of deleted leaf
nodes' parents.  This enabled the following sequence of events to
happen:

 1. Node A, which is a leaf node, is passed to send_to_prune_tree() and
    its pruning is queued.

 2. Node B is added to the RBTDB as a child of node A before the latter
    gets pruned.

 3. Node B, which is now a leaf node itself (and is likely to belong to
    a different node bucket than node A), is passed to
    send_to_prune_tree() and its pruning gets queued.

 4. Node B gets pruned.  Its parent, node A, now becomes a leaf again
    and therefore the prune_tree() call that handled node B calls
    send_to_prune_tree() for node A.

 5. Since node A was already queued for pruning in step 1 (but not yet
    pruned), the INSIST(!ISC_LINK_LINKED(node, prunelink)); assertion
    fails for node A in send_to_prune_tree().

The above sequence of events is not a sign of pathological behavior.
Replace the assertion check with a conditional early return from
send_to_prune_tree().

(cherry picked from commit f6289ad93141a29443d1e8e9874e36d44f16e686)

lib/dns/rbtdb.c

index ff9dc091995e4d178bee53d4140252a40b3b0393..f18a3581289b91e40fb77a3b4850e3b412969e79 100644 (file)
@@ -1980,7 +1980,9 @@ send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
                   isc_rwlocktype_t nlocktype) {
        bool pruning_queued = !ISC_LIST_EMPTY(rbtdb->prunenodes[node->locknum]);
 
-       INSIST(!ISC_LINK_LINKED(node, prunelink));
+       if (ISC_LINK_LINKED(node, prunelink)) {
+               return;
+       }
 
        new_reference(rbtdb, node, nlocktype);
        ISC_LIST_APPEND(rbtdb->prunenodes[node->locknum], node, prunelink);