From: Frederic Lecaille Date: Wed, 28 Oct 2026 10:26:02 +0000 (+0100) Subject: BUG/MEDIUM: ssl-gencert: fix a NULL dereference with QUIC listeners X-Git-Tag: v3.5-dev10~10 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=869308906f3d0315da3463c8037b7cd2e67a4190;p=haproxy.git BUG/MEDIUM: ssl-gencert: fix a NULL dereference with QUIC listeners ssl_sock_generate_certificate_from_conn() retrieves the connection from the SSL object through ssl_app_data_index. A QUIC SSL object only carries the quic_conn, stored under ssl_qc_app_data_index, so the connection is always NULL there and conn_get_dst() dereferences a NULL pointer. This function is called from ssl_sock_switchctx_cbk() when the ClientHello has no SNI and 'generate-certificates' is set on the bind line. Any client that omits the server_name extension therefore kills the worker (SIGSEGV), with no skill required: connecting to an IP address is enough, since RFC 6066 forbids IP literals in SNI. The bug is not specific to the OpenSSL compatibility layer. It reproduces with USE_QUIC=1 whether or not USE_QUIC_OPENSSL_COMPAT is set: the callback is registered the same way (HAVE_SSL_CLIENT_HELLO_CB) and the ex_data assignment in qc_ssl_sess_init() is identical. It was reproduced on a quictls build (USE_QUIC=1 alone, no 'limited-quic' needed) and on an OpenSSL build with USE_QUIC_OPENSSL_COMPAT=1, both crashing in ssl_sock_generate_certificate_from_conn(). Use ssl_sock_get_conn(), which handles both the connection and the quic_conn, and fall back on the quic_conn's local address, the QUIC counterpart of conn->dst, when there is no connection. When no address is available, return 0 so that the caller keeps its default certificate selection instead of crashing. This must be backported to all stable versions. Reported-by: Martin Mirchev --- diff --git a/src/ssl_gencert.c b/src/ssl_gencert.c index 4bff2d2d8..39e6fc7f7 100644 --- a/src/ssl_gencert.c +++ b/src/ssl_gencert.c @@ -424,13 +424,26 @@ error: int ssl_sock_generate_certificate_from_conn(struct bind_conf *bind_conf, SSL *ssl) { uint64_t key; - struct connection *conn = SSL_get_ex_data(ssl, ssl_app_data_index); + struct connection *conn = ssl_sock_get_conn(ssl, NULL); +#ifdef USE_QUIC + struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); +#endif + struct sockaddr_storage *dst = NULL; + + if (conn && conn_get_dst(conn)) + dst = conn->dst; +#ifdef USE_QUIC + else if (!conn && qc) + dst = &qc->local_addr; +#endif + + if (!dst) + return 0; + + key = ssl_sock_generated_cert_key(dst, get_addr_len(dst)); + if (ssl_sock_assign_generated_cert(key, bind_conf, ssl)) + return 1; - if (conn_get_dst(conn)) { - key = ssl_sock_generated_cert_key(conn->dst, get_addr_len(conn->dst)); - if (ssl_sock_assign_generated_cert(key, bind_conf, ssl)) - return 1; - } return 0; }