Commit 4965410125 for openssl.org
commit 49654101253fc0b69c87d3075343aba7e547c91a
Author: Neil Horman <nhorman@openssl.org>
Date: Thu Nov 5 15:25:44 2026 -0500
test/quicapitest.c: add a test for QUIC SSL object IPv6 peer address retrival
Make sure that, when peer address detection is in use,
we do not inadvertenly return uninitialized data.
References: CVE-2026-88822
References: https://github.com/openssl/openssl/issues/33457
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com>
Merge-date: Sat Nov 7 15:35:06 2026
Merged-from: https://github.com/openssl/openssl/pull/33566
diff --git a/test/quicapitest.c b/test/quicapitest.c
index f4b860dda9..535b7a107c 100644
--- a/test/quicapitest.c
+++ b/test/quicapitest.c
@@ -27,6 +27,7 @@
#include "internal/quic_port.h"
#include "internal/quic_txp.h"
#include "internal/quic_cc.h"
+#include "internal/bio_addr.h"
static OSSL_LIB_CTX *libctx = NULL;
static char *propq = NULL;
@@ -42,6 +43,9 @@ static char *datadir = NULL;
static int is_fips = 0;
static BIO_ADDR *create_addr(struct in_addr *ina, short int port);
+#if OPENSSL_USE_IPV6
+static BIO_ADDR *create_addr6(struct in6_addr *ina, short int port);
+#endif
static int bio_addr_bind(BIO *bio, BIO_ADDR *addr);
static SSL *ql_create(SSL_CTX *ssl_ctx, BIO *bio);
static SSL_CTX *create_server_ctx(void);
@@ -2735,6 +2739,24 @@ static BIO_ADDR *create_addr(struct in_addr *ina, short int port)
return addr;
}
+#if OPENSSL_USE_IPV6
+static BIO_ADDR *create_addr6(struct in6_addr *ina, short int port)
+{
+ BIO_ADDR *addr = NULL;
+
+ if (!TEST_ptr(addr = BIO_ADDR_new()))
+ return NULL;
+
+ if (!TEST_true(BIO_ADDR_rawmake(addr, AF_INET6, ina, sizeof(struct in6_addr),
+ htons(port)))) {
+ BIO_ADDR_free(addr);
+ return NULL;
+ }
+
+ return addr;
+}
+#endif
+
static int bio_addr_bind(BIO *bio, BIO_ADDR *addr)
{
int bio_caps = BIO_DGRAM_CAP_HANDLES_DST_ADDR | BIO_DGRAM_CAP_HANDLES_SRC_ADDR;
@@ -4983,6 +5005,174 @@ static int test_quic_peer_addr_v6(void)
"::1", 4433,
"::2", 4434);
}
+
+/*
+ * Test to ensure the use of getpeername in dgram bios
+ * doesn't return uninitialized data
+ */
+static int test_quic_detect_peer_addr_v6(void)
+{
+ int ret = 0;
+ BIO *cbio = NULL, *sbio = NULL;
+ int csock, ssock;
+ BIO_ADDR *caddr = NULL, *saddr = NULL;
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *client = NULL, *server = NULL;
+ struct in6_addr v6addr = IN6ADDR_LOOPBACK_INIT;
+ int rc, i;
+ static unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
+ BIO_ADDR test_addr = { 0 };
+ int serr;
+ SSL *sconn = NULL;
+
+ /*
+ * Create 2 ipv6 addresses
+ */
+ caddr = create_addr6(&v6addr, 4080);
+ saddr = create_addr6(&v6addr, 8040);
+
+ if (!TEST_ptr(caddr) || !TEST_ptr(saddr)) {
+ ret = TEST_skip("Platform can't create ipv6 addresses");
+ goto out;
+ }
+
+ /*
+ * Create udp sockets for each, set them to nonblocking
+ * bind them to their respective addresses
+ */
+ csock = BIO_socket(BIO_ADDR_family(caddr), SOCK_DGRAM, IPPROTO_UDP, 0);
+ ssock = BIO_socket(BIO_ADDR_family(saddr), SOCK_DGRAM, IPPROTO_UDP, 0);
+
+ if (!TEST_int_ne(csock, INVALID_SOCKET) || !TEST_int_ne(ssock, INVALID_SOCKET)) {
+ ret = TEST_skip("Platform can't create ipv6 sockets");
+ BIO_closesocket(csock);
+ BIO_closesocket(ssock);
+ goto out;
+ }
+ if (!TEST_true(BIO_socket_nbio(csock, 1))
+ || !TEST_true(BIO_socket_nbio(ssock, 1))) {
+ BIO_closesocket(csock);
+ BIO_closesocket(ssock);
+ goto out;
+ }
+
+ if (!TEST_true(BIO_bind(csock, caddr, BIO_SOCK_REUSEADDR))
+ || !TEST_true(BIO_bind(ssock, saddr, BIO_SOCK_REUSEADDR))) {
+ ret = TEST_skip("Platform can't bind ipv6 addresses");
+ BIO_closesocket(csock);
+ BIO_closesocket(ssock);
+ goto out;
+ }
+
+ /*
+ * Note we must use dgram bios here, not dgram bio pairs, as we
+ * need the bio to call getpeername when we use the DETECT ctrl below
+ */
+ cbio = BIO_new_dgram(csock, BIO_CLOSE);
+ if (!TEST_ptr(cbio)) {
+ /*
+ * If we can't bind the bio to an ipv6 socket, then
+ * this platform doesn't support ipv6
+ */
+ BIO_closesocket(csock);
+ BIO_closesocket(ssock);
+ ret = TEST_skip("Platform does not support IPv6");
+ goto out;
+ }
+ sbio = BIO_new_dgram(ssock, BIO_CLOSE);
+ if (!TEST_ptr(sbio)) {
+ BIO_closesocket(ssock);
+ goto out;
+ }
+
+ /*
+ * Setup out SSL contexts and objects
+ */
+ if (!TEST_ptr(sctx = create_server_ctx())
+ || !TEST_ptr(cctx = create_client_ctx()))
+ goto out;
+ if (!TEST_ptr((server = SSL_new_listener(sctx, 0)))
+ || !TEST_ptr(client = SSL_new(cctx)))
+ goto out;
+
+ /*
+ * Connect the socket before starting the SSL connection,
+ * doing so drives the BIO to auto detect the peer address
+ * When the SSL handshake starts.
+ * If we set it locally before the SSL_connect, then the QUIC
+ * stack has no need to auto detect.
+ */
+ if (!TEST_true(BIO_connect(csock, saddr, 0)))
+ goto out;
+
+ SSL_set_bio(server, sbio, sbio);
+ SSL_set_bio(client, cbio, cbio);
+ cbio = sbio = NULL;
+
+ if (!TEST_false(SSL_set_alpn_protos(client, alpn, sizeof(alpn))))
+ goto out;
+
+ if (!TEST_true(SSL_listen(server)))
+ goto out;
+ if (!TEST_true(SSL_set_blocking_mode(client, 0)))
+ goto out;
+
+ if (!TEST_true(SSL_set_tlsext_host_name(client, "localhost")))
+ goto out;
+
+ /*
+ * Send ClientHello and server retry. The connection doesn't actually
+ * have to complete, it just needs to start connecting so that QUIC detects
+ * the peer address.
+ */
+ for (i = 0; i < 5; i++) {
+ rc = SSL_connect(client);
+ if (rc <= 0) {
+ serr = SSL_get_error(client, rc);
+
+ if (serr == SSL_ERROR_SYSCALL) {
+ if (!TEST_true(SSL_get_peer_addr(client, &test_addr))
+ || !TEST_mem_eq(&test_addr.s_in6.sin6_addr,
+ sizeof(struct in6_addr),
+ &saddr->s_in6.sin6_addr, sizeof(struct in6_addr)))
+ goto out;
+ ret = TEST_skip("Platform does not support operating on connected sockets");
+ goto out;
+ }
+ if (!TEST_int_eq(serr, SSL_ERROR_WANT_READ))
+ goto out;
+ }
+ SSL_handle_events(server);
+ sconn = SSL_accept_connection(server, SSL_ACCEPT_CONNECTION_NO_BLOCK);
+ if (sconn != NULL) {
+ TEST_info("Connection established\n");
+ break;
+ }
+ }
+
+ /*
+ * Fetch the peer address and compare it to the server address we allocated
+ * above, making sure that they match
+ */
+ if (!TEST_true(SSL_get_peer_addr(client, &test_addr)))
+ goto out;
+ if (!TEST_mem_eq(&test_addr.s_in6.sin6_addr, sizeof(struct in6_addr),
+ &saddr->s_in6.sin6_addr, sizeof(struct in6_addr)))
+ goto out;
+ ret = 1;
+
+out:
+ SSL_free(server);
+ SSL_free(client);
+ SSL_free(sconn);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ BIO_free(cbio);
+ BIO_free(sbio);
+ BIO_ADDR_free(caddr);
+ BIO_ADDR_free(saddr);
+ return ret;
+}
#endif
/*
@@ -5549,6 +5739,7 @@ int setup_tests(void)
ADD_TEST(test_client_hello_retry);
#if OPENSSL_USE_IPV6
ADD_TEST(test_quic_peer_addr_v6);
+ ADD_TEST(test_quic_detect_peer_addr_v6);
#endif
ADD_TEST(test_quic_peer_addr_v4);
ADD_MFAIL_NO_CHECK_TEST(test_quic_handshake_multipkt_mfail);