]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Prevent freeing of parent listener in SSL_listen_ex master
authorNeil Horman <nhorman@openssl.org>
Mon, 15 Dec 2025 13:43:32 +0000 (08:43 -0500)
committerNeil Horman <nhorman@openssl.org>
Tue, 16 Dec 2025 15:18:37 +0000 (10:18 -0500)
Its been reported that, when using SSL_listen_ex to obtain a new
connection from a listener, that, if the listener is freed prior to the
obtained connection, we get use-after-free conditions when freeing said
obtained connections.

This occurs because SSL_listen_ex fails to take a reference on the
parent listener SSL object (in the same way that SSL_new_from_listener
does).  If the listener is freed first, then several listener resources
are freed, which the obtained connection still makes use of, hence the
use-after-free.

The fix is to do what SSL_new_from_listener does, namely:
1) Increase the reference count on the listener SSL object.
2) Ensure that the connection qc->listener points to the listener object
   so that, when the connection is freed, we call SSL_free on the
   listener object, dropping the reference count we take in
   SSL_listen_ex.

While we're at it, this PR also modifies the quicapi test for testing
the SSL_listen_ex call, freeing the listener first to ensure that the
increased refcount holds the SSL object data stable until the connection
is freed.

Thanks to Stanislav Fort at Asile Research for pointing out this issue.

fixes openssl/project#1766

Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/29398)

ssl/quic/quic_impl.c
test/quicapitest.c

index 53bb247e853f19b1fa4138955a9382cc5bee8736..87c1370a8d6db864333d9eb64493f76e611a0d07 100644 (file)
@@ -4670,9 +4670,21 @@ int ossl_quic_peeloff_conn(SSL *listener, SSL *new_conn)
 
         qc = cctx.qc;
         ql = lctx.ql;
 
         qc = cctx.qc;
         ql = lctx.ql;
+        /*
+         * Need to ensure that we take a reference on our new listener
+         * so that we don't free it before this connection
+         */
+        if (!SSL_up_ref(&ql->obj.ssl))
+            goto out;
+
         ossl_quic_channel_free(qc->ch);
         ossl_quic_port_free(qc->port);
         ossl_quic_engine_free(qc->engine);
         ossl_quic_channel_free(qc->ch);
         ossl_quic_port_free(qc->port);
         ossl_quic_engine_free(qc->engine);
+        /*
+         * Ensure that we point to our listener so we can drop
+         * the above refcount when this SSL object is freed
+         */
+        qc->listener = ql;
         qc->obj.engine = ql->engine;
         qc->engine = ql->engine;
         qc->port = ql->port;
         qc->obj.engine = ql->engine;
         qc->engine = ql->engine;
         qc->port = ql->port;
index 26d80d1a4b13cb70ad6c947e84e5c9e365e57071..d311ec65da30a6ba794cedc184c8ad0e97eacf09 100644 (file)
@@ -2910,9 +2910,9 @@ static int test_ssl_listen_ex(void)
     testresult = 1;
 
 err:
     testresult = 1;
 
 err:
+    SSL_free(qlistener);
     SSL_free(serverssl);
     SSL_free(clientssl);
     SSL_free(serverssl);
     SSL_free(clientssl);
-    SSL_free(qlistener);
     SSL_CTX_free(sctx);
     SSL_CTX_free(cctx);
     SSL_CTX_free(qmctx);
     SSL_CTX_free(sctx);
     SSL_CTX_free(cctx);
     SSL_CTX_free(qmctx);