From: William Lallemand Date: Tue, 27 Oct 2026 14:32:47 +0000 (+0000) Subject: BUG/MINOR: ssl: fix a double-free of the .sctl buffer with several contexts X-Git-Tag: v3.5-dev10~7 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=5a3a2c9be490d3891c7684b0e4bf37b351541ba7;p=haproxy.git BUG/MINOR: ssl: fix a double-free of the .sctl buffer with several contexts ssl_sock_load_sctl() stores the ckch's .sctl buffer in SSL_CTX ex_data, whose free callback releases it when the context is destroyed. The ckch also frees this buffer, causing a double-free during deinit or "haproxy -c", even with a single bind and certificate. Sharing the certificate across contexts adds further frees of the same buffer. Give each context its own copy, leaving the original owned by the ckch. AWS-LC already copies the list through its native API. This bug was introduced in 2.1 by commit 0dfae6c315 ("MINOR: ssl: load sctl from buf OR from a file") and must be backported to all versions since then. --- diff --git a/src/ssl_sock.c b/src/ssl_sock.c index f3bd0f5fd..3bcb70e79 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -1707,7 +1707,9 @@ static __maybe_unused int ssl_sock_sctl_parse_cbk(SSL *s, unsigned int ext_type, #endif /* HAVE_SSL_CTX_ADD_SERVER_CUSTOM_EXT */ -/* Attaches to . Returns 0 on success or -1 on failure. */ +/* Copies into , leaving ownership with the caller. Returns 0 + * on success or -1 on allocation, storage or library validation failure. + */ static int ssl_sock_load_sctl(SSL_CTX *ctx, struct buffer *sctl) { #ifdef HAVE_SSL_CTX_SET_SIGNED_CERT_TIMESTAMP_LIST @@ -1716,8 +1718,23 @@ static int ssl_sock_load_sctl(SSL_CTX *ctx, struct buffer *sctl) return -1; return 0; #else - if (!SSL_CTX_set_ex_data(ctx, sctl_ex_index, sctl)) + struct buffer *sctl_ctx; + + /* The ex_data free callback owns this copy; the ckch keeps the original. */ + sctl_ctx = calloc(1, sizeof(*sctl_ctx)); + if (!sctl_ctx) + return -1; + + if (!chunk_dup(sctl_ctx, sctl)) { + free(sctl_ctx); return -1; + } + + if (!SSL_CTX_set_ex_data(ctx, sctl_ex_index, sctl_ctx)) { + chunk_destroy(sctl_ctx); + free(sctl_ctx); + return -1; + } return 0; #endif }