Commit e0a65e5240 for openssl.org

commit e0a65e5240b4d69b1f7b168f9a84e10618b50082
Author: Nicky Mouha <nicky@mouha.be>
Date:   Wed Oct 28 13:30:50 2026 -0400

    test/dtlsssllistenertest.c: use mutex for accessing urxe_pending queue

    The urxe_pending queue in DTLS_RX is protected by rx->mutex.

    Add the mutex around the four remaining accesses
    in idle_pending_state_cb(), redrive_idle_cb(),
    test_dtls_listener_rx_queue_drops_oldest(),
    and test_dtls_listener_flood_then_handshake_int().

    These accesses occur in single-threaded tests, so mutexes
    are not required.  However, using the same queue locking
    pattern in both the library code and the tests is good
    practice and avoids Coverty alerts.

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Merge-date: Tue Nov 10 05:25:28 2026
    Merged-from: https://github.com/openssl/openssl/pull/33439

diff --git a/test/dtlsssllistenertest.c b/test/dtlsssllistenertest.c
index 9b327f1fc6..c3cdfca811 100644
--- a/test/dtlsssllistenertest.c
+++ b/test/dtlsssllistenertest.c
@@ -6937,6 +6937,7 @@ static int test_dtls_listener_rx_queue_drops_oldest(void)
     BIO_ADDR *client_addr = NULL;
     BIO *client_bio;
     SSL_CONNECTION *sc;
+    DTLS_RX *rx;
     SSL_POLL_ITEM poll_item;
     struct timeval poll_timeout;
     size_t poll_result, queued, i;
@@ -6992,15 +6993,23 @@ static int test_dtls_listener_rx_queue_drops_oldest(void)
     }

     if (!TEST_ptr(sc = SSL_CONNECTION_FROM_SSL_ONLY(serverssl))
-        || !TEST_ptr(sc->listener_rx))
+        || !TEST_ptr(rx = sc->listener_rx))
         goto end;
-    queued = ossl_list_urxe_num(&sc->listener_rx->urxe_pending);
+    /*
+     * This test is single-threaded, but a mutex lock follows the normal
+     * queue access pattern.
+     */
+    ossl_crypto_mutex_lock(rx->mutex);
+    queued = ossl_list_urxe_num(&rx->urxe_pending);
+    head = ossl_list_urxe_head(&rx->urxe_pending);
+    tail = ossl_list_urxe_tail(&rx->urxe_pending);
+    ossl_crypto_mutex_unlock(rx->mutex);
+
     if (!TEST_size_t_eq(queued, cap))
         goto end;

     /* The oldest datagrams were evicted: only the newest cap ones remain. */
-    if (!TEST_ptr(head = ossl_list_urxe_head(&sc->listener_rx->urxe_pending))
-        || !TEST_ptr(tail = ossl_list_urxe_tail(&sc->listener_rx->urxe_pending)))
+    if (!TEST_ptr(head) || !TEST_ptr(tail))
         goto end;
     head_data = ossl_dgram_urxe_data(head);
     tail_data = ossl_dgram_urxe_data(tail);
@@ -7392,6 +7401,7 @@ static int test_dtls_listener_flood_then_handshake_int(int version)
     int server_fd = -1, client_fd = -1, client2_fd = -1;
     DTLS_LISTENER *dl;
     SSL_CONNECTION *sc;
+    DTLS_RX *rx;
     unsigned char garbage[1200];
     size_t queued, i;
     int testresult = 0, k;
@@ -7443,9 +7453,15 @@ static int test_dtls_listener_flood_then_handshake_int(int version)

     /* The receive queue is exactly at its cap, not at the flood size. */
     if (!TEST_ptr(sc = SSL_CONNECTION_FROM_SSL_ONLY(serverssl))
-        || !TEST_ptr(sc->listener_rx))
+        || !TEST_ptr(rx = sc->listener_rx))
         goto end;
-    queued = ossl_list_urxe_num(&sc->listener_rx->urxe_pending);
+    /*
+     * This test is single-threaded, but a mutex lock follows the normal
+     * queue access pattern.
+     */
+    ossl_crypto_mutex_lock(rx->mutex);
+    queued = ossl_list_urxe_num(&rx->urxe_pending);
+    ossl_crypto_mutex_unlock(rx->mutex);
     if (!TEST_size_t_eq(queued, cap))
         goto end;

@@ -7627,6 +7643,7 @@ static void idle_pending_state_cb(SSL *ssl, const BIO_ADDR *peer, void *arg)
 {
     IDLE_PENDING_STATE *st = arg;
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
+    DTLS_RX *rx;

     if (sc == NULL || sc->listener_rx == NULL) {
         st->queued++;
@@ -7635,8 +7652,15 @@ static void idle_pending_state_cb(SSL *ssl, const BIO_ADDR *peer, void *arg)
     if (sc->hello_retry_request == SSL_HRR_PENDING
         || sc->statem.hand_state == DTLS_ST_SW_HELLO_VERIFY_REQUEST)
         st->retry_sent++;
-    if (!ossl_list_urxe_is_empty(&sc->listener_rx->urxe_pending))
+    rx = sc->listener_rx;
+    /*
+     * This test is single-threaded, but a mutex lock follows the normal queue
+     * access pattern.
+     */
+    ossl_crypto_mutex_lock(rx->mutex);
+    if (!ossl_list_urxe_is_empty(&rx->urxe_pending))
         st->queued++;
+    ossl_crypto_mutex_unlock(rx->mutex);
 }

 /*
@@ -7829,10 +7853,19 @@ static void redrive_ch_cb(int write_p, int version, int content_type,
 static void redrive_idle_cb(SSL *ssl, const BIO_ADDR *peer, void *arg)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(ssl);
+    DTLS_RX *rx;

-    if (sc != NULL && sc->listener_idle && sc->listener_rx != NULL
-        && ossl_list_urxe_is_empty(&sc->listener_rx->urxe_pending))
-        (*(size_t *)arg)++;
+    if (sc != NULL && sc->listener_idle && sc->listener_rx != NULL) {
+        rx = sc->listener_rx;
+        /*
+         * This test is single-threaded, but a mutex lock follows the normal
+         * queue access pattern.
+         */
+        ossl_crypto_mutex_lock(rx->mutex);
+        if (ossl_list_urxe_is_empty(&rx->urxe_pending))
+            (*(size_t *)arg)++;
+        ossl_crypto_mutex_unlock(rx->mutex);
+    }
 }

 /* Are all |n| pending connections waiting for their peers? */