From 7d4aa7b22bdb0c414c6efdcd84c5c4d317c620dd Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Tue, 4 Nov 2025 16:46:50 +0100 Subject: [PATCH] BUG/MEDIUM: server: Add a rwlock to path parameter Add a rwlock to control the server's path_parameter, to make sure multiple threads don't set it at the same time, and it can't be seen in an inconsistent state. Also don't set the parameter every time, only set them if they have changed, to prevent needless writes. This does not need to be backported. --- include/haproxy/server-t.h | 1 + src/backend.c | 12 ++++++++---- src/server.c | 3 +++ src/ssl_sock.c | 10 +++++++--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index e2036c9c7..668861908 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -320,6 +320,7 @@ enum renegotiate_mode { #define MAX_ALPN_SIZE 16 struct path_parameters { + __decl_thread(HA_RWLOCK_T param_lock); char nego_alpn[MAX_ALPN_SIZE]; }; diff --git a/src/backend.c b/src/backend.c index 6412eb2b8..0a5637b4b 100644 --- a/src/backend.c +++ b/src/backend.c @@ -2067,10 +2067,14 @@ int connect_server(struct stream *s) * that this is skipped in TCP mode as we only want mux-pt * anyway. */ - if (IS_HTX_STRM(s) && srv && srv->use_ssl && - (srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str) && - srv->path_params.nego_alpn[0] == 0) - may_start_mux_now = 0; + if (srv) { + HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock); + if (IS_HTX_STRM(s) && srv->use_ssl && + (srv->ssl_ctx.alpn_str || srv->ssl_ctx.npn_str) && + srv->path_params.nego_alpn[0] == 0) + may_start_mux_now = 0; + HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock); + } #endif /* process the case where the server requires the PROXY protocol to be sent */ diff --git a/src/server.c b/src/server.c index ba0419316..7812a22d0 100644 --- a/src/server.c +++ b/src/server.c @@ -141,7 +141,9 @@ static const char *srv_op_st_chg_cause_str[] = { static void srv_reset_path_parameters(struct server *s) { + HA_RWLOCK_WRLOCK(SERVER_LOCK, &s->path_params.param_lock); s->path_params.nego_alpn[0] = 0; + HA_RWLOCK_WRUNLOCK(SERVER_LOCK, &s->path_params.param_lock); } const char *srv_op_st_chg_cause(enum srv_op_st_chg_cause cause) @@ -3142,6 +3144,7 @@ struct server *new_server(struct proxy *proxy) sv->next = srv; } + HA_RWLOCK_INIT(&srv->path_params.param_lock); /* please don't put default server settings here, they are set in * proxy_preset_defaults(). */ diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 0cdd6c77e..7e621bbe1 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -6825,11 +6825,15 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state) const char *alpn; int len; - if (ssl_sock_get_alpn(conn, ctx, &alpn, &len)) { - srv = objt_server(conn->target); - if (srv && len < sizeof(srv->path_params.nego_alpn)) { + srv = objt_server(conn->target); + if (srv && ssl_sock_get_alpn(conn, ctx, &alpn, &len)) { + if (len < sizeof(srv->path_params.nego_alpn) && + (len != strlen(srv->path_params.nego_alpn) || + memcmp(&srv->path_params.nego_alpn, alpn, len) != 0)) { + HA_RWLOCK_WRLOCK(SERVER_LOCK, &srv->path_params.param_lock); memcpy(&srv->path_params.nego_alpn, alpn, len); srv->path_params.nego_alpn[len] = 0; + HA_RWLOCK_WRUNLOCK(SERVER_LOCK, &srv->path_params.param_lock); } } } -- 2.47.3