Commit 31c32ca387 for openssl.org
commit 31c32ca387a01b1134b459941d5111ab977b8197
Author: Bob Beck <beck@openssl.org>
Date: Tue Aug 18 13:49:34 2026 -0600
Free connections before listeners in the radix test cleanup
A connection's assist thread reads from its network BIO, which for a
dgram BIO pair belongs to the linked listener. Freeing a listener while
the connection's assist thread is still running is a use-after-free.
Freeing connections first joins their assist threads, so no thread is
reading when the listener BIOs are freed.
Fixes #32420
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Merge-date: Fri Aug 21 11:06:40 2026
Merged-from: https://github.com/openssl/openssl/pull/32421
diff --git a/test/radix/quic_bindings.c b/test/radix/quic_bindings.c
index f31eb103a7..7b95d43f2d 100644
--- a/test/radix/quic_bindings.c
+++ b/test/radix/quic_bindings.c
@@ -439,6 +439,22 @@ static int RADIX_PROCESS_join_all_threads(RADIX_PROCESS *rp, int *testresult)
return ok;
}
+/*
+ * Free every non-listener object's SSL before cleanup_one() frees any listener.
+ *
+ * A connection's assist thread reads from its network BIO, and for a dgram BIO
+ * pair (see hf_link_dgram_pair) that BIO belongs to the linked listener. Freeing
+ * the connection joins its assist thread (see ossl_quic_free), so doing so first
+ * ensures no assist thread is still reading when the listener BIOs are freed.
+ */
+static void cleanup_nonlistener(RADIX_OBJ *obj)
+{
+ if (obj->ssl != NULL && !SSL_is_listener(obj->ssl)) {
+ SSL_free(obj->ssl);
+ obj->ssl = NULL;
+ }
+}
+
static void cleanup_one(RADIX_OBJ *obj)
{
obj->registered = 0;
@@ -459,6 +475,7 @@ static void RADIX_PROCESS_cleanup(RADIX_PROCESS *rp)
sk_RADIX_THREAD_free(rp->threads);
rp->threads = NULL;
+ lh_RADIX_OBJ_doall(rp->objs, cleanup_nonlistener);
lh_RADIX_OBJ_doall(rp->objs, cleanup_one);
lh_RADIX_OBJ_free(rp->objs);
rp->objs = NULL;