]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Revalidate the adbname when canceling the ADB find
authorOndřej Surý <ondrej@isc.org>
Tue, 5 Nov 2024 13:59:16 +0000 (14:59 +0100)
committerOndřej Surý <ondrej@isc.org>
Wed, 13 Nov 2024 07:18:39 +0000 (08:18 +0100)
When canceling the ADB find, the lock on the find gets released for
a brief period of time to be locked again inside adbname lock.  During
the brief period that the ADB find is unlocked, it can get canceled by
other means removing it from the adbname list which in turn causes
assertion failure due to a double removal from the adbname list.

Recheck if the find->adbname is still valid after acquiring the lock
again and if not just skip the double removal.  Additionally, attach to
the adbname as in the worst case, the adbname might also cease to exist
if the scheduler would block this particular thread for a longer period
of time invalidating the lock we are going to acquire and release.

lib/dns/adb.c

index d934e232d093609a9c271aa314da24657e51fa5a..6ab7816c023d490153ae82968a8ada9ea9576178 100644 (file)
@@ -2314,17 +2314,29 @@ dns_adb_cancelfind(dns_adbfind_t *find) {
                 * locks in that order, to match locking hierarchy
                 * elsewhere.
                 */
+               dns_adbname_ref(adbname);
                UNLOCK(&find->lock);
+
+               /*
+                * Other thread could cancel the find between the unlock and
+                * lock, so we need to recheck whether the adbname is still
+                * valid and reference the adbname, so it does not vanish before
+                * we have a chance to lock it again.
+                */
+
                LOCK(&adbname->lock);
                LOCK(&find->lock);
 
-               ISC_LIST_UNLINK(adbname->finds, find, plink);
-               find->adbname = NULL;
+               if (find->adbname != NULL) {
+                       ISC_LIST_UNLINK(find->adbname->finds, find, plink);
+                       find->adbname = NULL;
+               }
 
                find_sendevent(find);
 
                UNLOCK(&find->lock);
                UNLOCK(&adbname->lock);
+               dns_adbname_detach(&adbname);
        }
 }