BUG/MINOR: quic: release BE quic_conn on connect failure

If quic_connect_server() fails, quic_conn FD will remain unopened as set
to -1. Backend connections do not have a fallback socket for future
exchange, contrary to frontend one which can use the listener FD. As
such, it is better to release these connections early.

This patch adjusts such failure by extending quic_close(). This function
is called by the upper layer immediately after a connect issue. In this
case, release immediately a quic_conn backend instance if the FD is
unset, which means that connect has previously failed.

Also, quic_conn_release() is extended to ensure that such faulty
connections are immediately freed and not converted into a
quic_conn_closed instance.

Prior to this patch, a backend quic_conn without any FD would remain
allocated and possibly active. If its tasklet is executed, this resulted
in a crash due to access to an invalid FD.

No need to backport.
This commit is contained in:
Amaury Denoyelle 2025-11-25 14:37:50 +01:00
parent 346631700d
commit 6c08eb7173
2 changed files with 15 additions and 4 deletions

View File

@ -1548,9 +1548,16 @@ int quic_conn_release(struct quic_conn *qc)
BUG_ON(qc->conn);
cc_qc = NULL;
/* Convert to quic_conn_closed if entering in CLOSING state, except in
* the following case :
* - idle timeout already expired
* - no FD available for a backend connection (after connect() failure)
*/
if ((qc->flags & QUIC_FL_CONN_CLOSING) && !(qc->flags & QUIC_FL_CONN_EXP_TIMER) &&
qc->tx.cc_buf_area)
qc->tx.cc_buf_area &&
(!qc_is_back(qc) || qc_test_fd(qc))) {
cc_qc = qc_new_cc_conn(qc);
}
if (!cc_qc) {
task_destroy(qc->idle_timer_task);

View File

@ -14,6 +14,7 @@
#include <haproxy/buf.h>
#include <haproxy/connection.h>
#include <haproxy/quic_conn.h>
#include <haproxy/quic_sock.h>
#include <haproxy/quic_ssl.h>
#include <haproxy/ssl_sock.h>
#include <haproxy/quic_trace.h>
@ -42,10 +43,13 @@ static void quic_close(struct connection *conn, void *xprt_ctx)
qc->flags |= QUIC_FL_CONN_XPRT_CLOSED;
qc->conn = NULL;
/* If the quic-conn timer has already expired or if already in "connection close"
* state, free the quic-conn.
/* Immediately release the connection in the following cases :
* - idle timeout already expired
* - connection in closing state
* - backend conn with no FD avail (after connect() failure)
*/
if (qc->flags & (QUIC_FL_CONN_EXP_TIMER|QUIC_FL_CONN_CLOSING)) {
if (qc->flags & (QUIC_FL_CONN_EXP_TIMER|QUIC_FL_CONN_CLOSING) ||
(qc_is_back(qc) && !qc_test_fd(qc))) {
quic_conn_release(qc);
qc = NULL;
goto leave;