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;