From f6289ad93141a29443d1e8e9874e36d44f16e686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 29 Feb 2024 17:38:52 +0100 Subject: [PATCH] Gracefully handle resending a node to prune_tree() Commit 2df147cb1264b30c7f26c1d75310a010615687bc 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(). --- lib/dns/rbtdb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 380218cde9..9d1b4cd372 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -2004,7 +2004,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);