From: Christopher Faulet Date: Thu, 22 Oct 2026 08:12:11 +0000 (+0200) Subject: BUG/MEDIUM: connection: don't leak the fd of an accepted connection X-Git-Tag: v3.5-dev10~64 X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=ad082111a04b4387f8aa76e386a2f340f9583bd2;p=haproxy.git BUG/MEDIUM: connection: don't leak the fd of an accepted connection When session_accept_fd() fails in conn_prepare(), e.g. because the SSL connection limit (maxsslconn) is reached, conn_ctrl_init() hasn't run yet and CO_FL_CTRL_READY isn't set. conn_ctrl_close() then cannot close the fd, leaving it open. Additional incoming connections on the same listener keep accumulating leaked fds, even after the SSL connections are released, and may ultimately exhaust maxsock, also preventing non-SSL frontends from accepting. Fix this by closing the fd in conn_ctrl_close() when it hasn't been registered yet, unless the connection is fdless. Many thanks to Adam Crawford for the report. This should be backported to all supported versions. --- diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index e51f2b423..26dd404ce 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -196,13 +196,26 @@ static inline void conn_ctrl_init(struct connection *conn) */ static inline void conn_ctrl_close(struct connection *conn) { - if (!conn->xprt && (conn->flags & CO_FL_CTRL_READY)) { + if (conn->xprt) + return; + + if (conn->flags & CO_FL_CTRL_READY) { if ((conn->flags & (CO_FL_WANT_DRAIN | CO_FL_SOCK_RD_SH)) == CO_FL_WANT_DRAIN) conn_ctrl_drain(conn); conn->flags &= ~CO_FL_CTRL_READY; if (conn->ctrl->ctrl_close) conn->ctrl->ctrl_close(conn); } + else if (!(conn->flags & CO_FL_FDLESS) && conn->handle.fd != DEAD_FD_MAGIC) { + /* the connection got an accepted FD temporarily assigned but + * it was never inserted, thus it's not known from the fdtab. + * As soon as it's closed, it cannot be touched anymore as it + * may be re-assigned to another thread. + */ + close(conn->handle.fd); + conn->handle.fd = DEAD_FD_MAGIC; + } + } /* If the connection still has a transport layer, then call its close() function