diff --git a/Backport-CVE-2024-45506-BUG-MAJOR-mux-h2-always.patch b/Backport-CVE-2024-45506-BUG-MAJOR-mux-h2-always.patch deleted file mode 100644 index c9b2ed50d93e1e0364f86f47f6ab3f0ac2509d00..0000000000000000000000000000000000000000 --- a/Backport-CVE-2024-45506-BUG-MAJOR-mux-h2-always.patch +++ /dev/null @@ -1,91 +0,0 @@ -From c725db17e8416ffb3c1537aea756356228ce5e3c Mon Sep 17 00:00:00 2001 -From: Willy Tarreau -Date: Mon, 2 Sep 2024 15:18:51 +0200 -Subject: [PATCH] BUG/MAJOR: mux-h2: always clear MUX_MFULL and DEM_MROOM when - clearing the mbuf - -There exists an extremely tricky code path that was revealed in 3.0 by -the glitches feature, though it might theoretically have existed before. - -TL;DR: a mux mbuf may be full after successfully sending GOAWAY, and -discard its remaining contents without clearing H2_CF_MUX_MFULL and -H2_CF_DEM_MROOM, then endlessly loop in h2_send(), until the watchdog -takes care of it. - -What can happen is the following: Some data are received, h2_io_cb() is -called. h2_recv() is called to receive the incoming data. Then -h2_process() is called and in turn calls h2_process_demux() to process -input data. At some point, a glitch limit is reached and h2c_error() is -called to close the connection. The input frame was incomplete, so some -data are left in the demux buffer. Then h2_send() is called, which in -turn calls h2_process_mux(), which manages to queue the GOAWAY frame, -turning the state to H2_CS_ERROR2. The frame is sent, and h2_process() -calls h2_send() a last time (doing nothing) and leaves. The streams -are all woken up to notify about the error. - -Multiple backend streams were waiting to be scheduled and are woken up -in turn, before their parents being notified, and communicate with the -h2 mux in zero-copy-forward mode, request a buffer via h2_nego_ff(), -fill it, and commit it with h2_done_ff(). At some point the mux's output -buffer is full, and gets flags H2_CF_MUX_MFULL. - -The io_cb is called again to process more incoming data. h2_send() isn't -called (polled) or does nothing (e.g. TCP socket buffers full). h2_recv() -may or may not do anything (doesn't matter). h2_process() is called since -some data remain in the demux buf. It goes till the end, where it finds -st0 == H2_CS_ERROR2 and clears the mbuf. We're now in a situation where -the mbuf is empty and MFULL is still present. - -Then it calls h2_send(), which doesn't call h2_process_mux() due to -MFULL, doesn't enter the for() loop since all buffers are empty, then -keeps sent=0, which doesn't allow to clear the MFULL flag, and since -"done" was not reset, it loops forever there. - -Note that the glitches make the issue more reproducible but theoretically -it could happen with any other GOAWAY (e.g. PROTOCOL_ERROR). What makes -it not happen with the data produced on the parsing side is that we -process a single buffer of input at once, and there's no way to amplify -this to 30 buffers of responses (RST_STREAM, GOAWAY, SETTINGS ACK, -WINDOW_UPDATE, PING ACK etc are all quite small), and since the mbuf is -cleared upon every exit from h2_process() once the error was sent, it is -not possible to accumulate response data across multiple calls. And the -regular h2_snd_buf() path checks for st0 >= H2_CS_ERROR so it will not -produce any data there either. - -Probably that h2_nego_ff() should check for H2_CS_ERROR before accepting -to deliver a buffer, but this needs to be carefully studied. In the mean -time the real problem is that the MFULL flag was kept when clearing the -buffer, making the two inconsistent. - -Since it doesn't seem possible to trigger this sequence without the -zero-copy-forward mechanism, this fix needs to be backported as far as -2.9, along with previous commit "MINOR: mux-h2: try to clear DEM_MROOM -and MUX_MFULL at more places" which will strengthen the consistency -between these checks. - -Many thanks to Annika Wickert for her detailed report that allowed to -diagnose this problem. CVE-2024-45506 was assigned to this problem. - -(cherry picked from commit 830e50561c6636be4ada175d03e8df992abbbdcd) -Signed-off-by: Willy Tarreau ---- - src/mux_h2.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/mux_h2.c b/src/mux_h2.c -index d098a8c..c54ee18 100644 ---- a/src/mux_h2.c -+++ b/src/mux_h2.c -@@ -827,6 +827,9 @@ static inline void h2_release_mbuf(struct h2c *h2c) - b_free(buf); - count++; - } -+ -+ h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM); -+ - if (count) - offer_buffers(NULL, count); - } --- -2.43.0 - diff --git a/CVE-2024-49214.patch b/CVE-2024-49214.patch deleted file mode 100644 index e4160eef4a1b59f9c825ba39281191e5151f51ce..0000000000000000000000000000000000000000 --- a/CVE-2024-49214.patch +++ /dev/null @@ -1,458 +0,0 @@ -From fe5685af820ae62fe5b0d80b5ed7a2ffc41a036f Mon Sep 17 00:00:00 2001 -From: Frederic Lecaille -Date: Fri, 30 Aug 2024 15:38:54 +0200 -Subject: [PATCH] BUG/MEDIUM: quic: always validate sender address on 0-RTT - -It has been reported by Wedl Michael, a student at the University of Applied -Sciences St. Poelten, a potential vulnerability into haproxy as described below. - -An attacker could have obtained a TLS session ticket after having established -a connection to an haproxy QUIC listener, using its real IP address. The -attacker has not even to send a application level request (HTTP3). Then -the attacker could open a 0-RTT session with a spoofed IP address -trusted by the QUIC listen to bypass IP allow/block list and send HTTP3 requests. - -To mitigate this vulnerability, one decided to use a token which can be provided -to the client each time it successfully managed to connect to haproxy. These -tokens may be reused for future connections to validate the address/path of the -remote peer as this is done with the Retry token which is used for the current -connection, not the next one. Such tokens are transported by NEW_TOKEN frames -which was not used at this time by haproxy. - -So, each time a client connect to an haproxy QUIC listener with 0-RTT -enabled, it is provided with such a token which can be reused for the -next 0-RTT session. If no such a token is presented by the client, -haproxy checks if the session is a 0-RTT one, so with early-data presented -by the client. Contrary to the Retry token, the decision to refuse the -connection is made only when the TLS stack has been provided with -enough early-data from the Initial ClientHello TLS message and when -these data have been accepted. Hopefully, this event arrives fast enough -to allow haproxy to kill the connection if some early-data have been accepted -without token presented by the client. - -quic_build_post_handshake_frames() has been modified to build a NEW_TOKEN -frame with this newly implemented token to be transported inside. - -quic_tls_derive_retry_token_secret() was renamed to quic_do_tls_derive_token_secre() -and modified to be reused and derive the secret for the new token implementation. - -quic_token_validate() has been implemented to validate both the Retry and -the new token implemented by this patch. When this is a non-retry token -which could not be validated, the datagram received is marked as requiring -a Retry packet to be sent, and no connection is created. - -When the Initial packet does not embed any non-retry token and if 0-RTT is enabled -the connection is marked with this new flag: QUIC_FL_CONN_NO_TOKEN_RCVD. As soon -as the TLS stack detects that some early-data have been provided and accepted by -the client, the connection is marked to be killed (QUIC_FL_CONN_TO_KILL) from -ha_quic_add_handshake_data(). This is done calling qc_ssl_eary_data_accepted() -new function. The secret TLS handshake is interrupted as soon as possible returnin -0 from ha_quic_add_handshake_data(). The connection is also marked as -requiring a Retry packet to be sent (QUIC_FL_CONN_SEND_RETRY) from -ha_quic_add_handshake_data(). The the handshake I/O handler (quic_conn_io_cb()) -knows how to behave: kill the connection after having sent a Retry packet. - -About TLS stack compatibility, this patch is supported by aws-lc. It is -disabled for wolfssl which does not support 0-RTT at this time thanks -to HAVE_SSL_0RTT_QUIC. - -This patch depends on these commits: - - MINOR: quic: Add trace for QUIC_EV_CONN_IO_CB event. - MINOR: quic: Implement qc_ssl_eary_data_accepted(). - MINOR: quic: Modify NEW_TOKEN frame structure (qf_new_token struct) - BUG/MINOR: quic: Missing incrementation in NEW_TOKEN frame builder - MINOR: quic: Token for future connections implementation. - MINOR: quic: Implement quic_tls_derive_token_secret(). - MINOR: tools: Implement ipaddrcpy(). - -Must be backported as far as 2.6. - -(cherry picked from commit f627b9272bd8ffca6f2f898bfafc6bf0b84b7d46) -[fl: Add ->flags to quic_dgram struct (would arrive with quic_initial feature). - Add QUIC_DGRAM_FL_ quic_dgram flags (would arrive with quic_initial feature). - Modify quic_rx_pkt_retrieve_conn() to fix a compilation issue and correctly - handle the "if (pkt->token_len) {}" else block to do so with quic_initial - feature] -Signed-off-by: Frederic Lecaille -(cherry picked from commit e875aa59a9216d42639b802b5008afc733e4c940) -[wt: move QUIC_CONN_FL_* upper in quic_conn-t.h; ctx adj in quic_dgram; - include quic_cid-t for struct quic_cid in quic_rx-t.h] -Signed-off-by: Willy Tarreau ---- - include/haproxy/quic_conn-t.h | 3 ++ - include/haproxy/quic_rx-t.h | 2 ++ - include/haproxy/quic_sock-t.h | 5 +++ - src/quic_conn.c | 65 ++++++++++++++++++++++++++++++--- - src/quic_retry.c | 8 +---- - src/quic_rx.c | 80 +++++++++++++++++++++++++++++++++++------ - src/quic_sock.c | 2 ++ - src/quic_ssl.c | 20 ++++++++++- - 8 files changed, 161 insertions(+), 24 deletions(-) - -diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h -index a126e04..382454c 100644 ---- a/include/haproxy/quic_conn-t.h -+++ b/include/haproxy/quic_conn-t.h -@@ -291,6 +291,9 @@ struct quic_conn_cntrs { - #define QUIC_FL_CONN_IPKTNS_DCD (1U << 15) /* Initial packet number space discarded */ - #define QUIC_FL_CONN_HPKTNS_DCD (1U << 16) /* Handshake packet number space discarded */ - #define QUIC_FL_CONN_PEER_VALIDATED_ADDR (1U << 17) /* Peer address is considered as validated for this connection. */ -+#define QUIC_FL_CONN_NO_TOKEN_RCVD (1U << 18) /* Client dit not send any token */ -+#define QUIC_FL_CONN_SEND_RETRY (1U << 19) /* A send retry packet must be sent */ -+/* gap here */ - #define QUIC_FL_CONN_TO_KILL (1U << 24) /* Unusable connection, to be killed */ - #define QUIC_FL_CONN_TX_TP_RECEIVED (1U << 25) /* Peer transport parameters have been received (used for the transmitting part) */ - #define QUIC_FL_CONN_FINALIZED (1U << 26) /* QUIC connection finalized (functional, ready to send/receive) */ -diff --git a/include/haproxy/quic_rx-t.h b/include/haproxy/quic_rx-t.h -index 9ef8e7a..e77755b 100644 ---- a/include/haproxy/quic_rx-t.h -+++ b/include/haproxy/quic_rx-t.h -@@ -1,6 +1,8 @@ - #ifndef _HAPROXY_RX_T_H - #define _HAPROXY_RX_T_H - -+#include -+ - extern struct pool_head *pool_head_quic_conn_rxbuf; - extern struct pool_head *pool_head_quic_dgram; - extern struct pool_head *pool_head_quic_rx_packet; -diff --git a/include/haproxy/quic_sock-t.h b/include/haproxy/quic_sock-t.h -index 67a5749..83ab32f 100644 ---- a/include/haproxy/quic_sock-t.h -+++ b/include/haproxy/quic_sock-t.h -@@ -25,6 +25,9 @@ struct quic_receiver_buf { - struct mt_list rxbuf_el; /* list element into receiver.rxbuf_list. */ - }; - -+#define QUIC_DGRAM_FL_REJECT 0x00000001 -+#define QUIC_DGRAM_FL_SEND_RETRY 0x00000002 -+ - /* QUIC datagram */ - struct quic_dgram { - void *owner; -@@ -38,6 +41,8 @@ struct quic_dgram { - - struct list recv_list; /* elemt to quic_receiver_buf . */ - struct mt_list handler_list; /* elem to quic_dghdlr . */ -+ -+ int flags; /* QUIC_DGRAM_FL_* values */ - }; - - /* QUIC datagram handler */ -diff --git a/src/quic_conn.c b/src/quic_conn.c -index cb56fbe..d9808d2 100644 ---- a/src/quic_conn.c -+++ b/src/quic_conn.c -@@ -56,6 +56,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -478,6 +479,30 @@ int quic_build_post_handshake_frames(struct quic_conn *qc) - } - - LIST_APPEND(&frm_list, &frm->list); -+ -+#ifdef HAVE_SSL_0RTT_QUIC -+ if (qc->li->bind_conf->ssl_conf.early_data) { -+ size_t new_token_frm_len; -+ -+ frm = qc_frm_alloc(QUIC_FT_NEW_TOKEN); -+ if (!frm) { -+ TRACE_ERROR("frame allocation error", QUIC_EV_CONN_IO_CB, qc); -+ goto leave; -+ } -+ -+ new_token_frm_len = -+ quic_generate_token(frm->new_token.data, -+ sizeof(frm->new_token.data), &qc->peer_addr); -+ if (!new_token_frm_len) { -+ TRACE_ERROR("token generation failed", QUIC_EV_CONN_IO_CB, qc); -+ goto leave; -+ } -+ -+ BUG_ON(new_token_frm_len != sizeof(frm->new_token.data)); -+ frm->new_token.len = new_token_frm_len; -+ LIST_APPEND(&frm_list, &frm->list); -+ } -+#endif - } - - /* Initialize connection IDs minus one: there is -@@ -759,6 +784,11 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) - qc_ssl_provide_all_quic_data(qc, qc->xprt_ctx); - } - -+ if (qc->flags & QUIC_FL_CONN_TO_KILL) { -+ TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_PHPKTS, qc); -+ goto out; -+ } -+ - /* Retranmissions */ - if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) { - TRACE_DEVEL("retransmission needed", QUIC_EV_CONN_PHPKTS, qc); -@@ -872,7 +902,25 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) - quic_nictx_free(qc); - } - -- if ((qc->flags & QUIC_FL_CONN_CLOSING) && qc->mux_state != QC_MUX_READY) { -+ if (qc->flags & QUIC_FL_CONN_SEND_RETRY) { -+ struct quic_counters *prx_counters; -+ struct proxy *prx = qc->li->bind_conf->frontend; -+ struct quic_rx_packet pkt = { -+ .scid = qc->dcid, -+ .dcid = qc->odcid, -+ }; -+ -+ prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module); -+ if (send_retry(qc->li->rx.fd, &qc->peer_addr, &pkt, qc->original_version)) { -+ TRACE_ERROR("Error during Retry generation", -+ QUIC_EV_CONN_LPKT, NULL, NULL, NULL, qc->original_version); -+ } -+ else -+ HA_ATOMIC_INC(&prx_counters->retry_sent); -+ } -+ -+ if ((qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_TO_KILL)) && -+ qc->mux_state != QC_MUX_READY) { - quic_conn_release(qc); - qc = NULL; - } -@@ -979,11 +1027,15 @@ struct task *qc_process_timer(struct task *task, void *ctx, unsigned int state) - * for QUIC servers (or haproxy listeners). - * is the destination connection ID, is the source connection ID. - * This latter CID as the same value on the wire as the one for -- * which is the first CID of this connection but a different internal representation used to build -+ * which is the first CID of this connection but a different internal -+ * representation used to build - * NEW_CONNECTION_ID frames. This is the responsibility of the caller to insert - * in the CIDs tree for this connection (qc->cids). -- * is the token found to be used for this connection with as -- * length. Endpoints addresses are specified via and . -+ * is a boolean denoting if a token was received for this connection -+ * from an Initial packet. -+ * is the original destination connection ID which was embedded -+ * into the Retry token sent to the client before instantiated this connection. -+ * Endpoints addresses are specified via and . - * Returns the connection if succeeded, NULL if not. - */ - struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, -@@ -1090,6 +1142,9 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, - qc->prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, - &quic_stats_module); - qc->flags = QUIC_FL_CONN_LISTENER; -+ /* Mark this connection as having not received any token when 0-RTT is enabled. */ -+ if (l->bind_conf->ssl_conf.early_data && !token) -+ qc->flags |= QUIC_FL_CONN_NO_TOKEN_RCVD; - qc->state = QUIC_HS_ST_SERVER_INITIAL; - /* Copy the client original DCID. */ - qc->odcid = *dcid; -@@ -1112,7 +1167,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, - /* If connection is instantiated due to an INITIAL packet with an - * already checked token, consider the peer address as validated. - */ -- if (token_odcid->len) { -+ if (token) { - TRACE_STATE("validate peer address due to initial token", - QUIC_EV_CONN_INIT, qc); - qc->flags |= QUIC_FL_CONN_PEER_VALIDATED_ADDR; -diff --git a/src/quic_retry.c b/src/quic_retry.c -index 2d6ea31..78ef88a 100644 ---- a/src/quic_retry.c -+++ b/src/quic_retry.c -@@ -258,17 +258,11 @@ int quic_retry_token_check(struct quic_rx_packet *pkt, - TRACE_ENTER(QUIC_EV_CONN_LPKT, qc); - - /* The caller must ensure this. */ -- BUG_ON(!pkt->token_len); -+ BUG_ON(!pkt->token_len || *pkt->token != QUIC_TOKEN_FMT_RETRY); - - prx = l->bind_conf->frontend; - prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module); - -- if (*pkt->token != QUIC_TOKEN_FMT_RETRY) { -- /* TODO: New token check */ -- TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version); -- goto leave; -- } -- - if (sizeof buf < tokenlen) { - TRACE_ERROR("too short buffer", QUIC_EV_CONN_LPKT, qc); - goto err; -diff --git a/src/quic_rx.c b/src/quic_rx.c -index 7bc5844..81eaa69 100644 ---- a/src/quic_rx.c -+++ b/src/quic_rx.c -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1587,6 +1588,47 @@ static inline int quic_padding_check(const unsigned char *pos, - return pos == end; - } - -+/* Validate the token, retry or not (provided by NEW_TOKEN) parsed into -+ * RX packet from datagram. -+ * Return 1 if succeded, 0 if not. -+ */ -+static inline int quic_token_validate(struct quic_rx_packet *pkt, -+ struct quic_dgram *dgram, -+ struct listener *l, struct quic_conn *qc, -+ struct quic_cid *odcid) -+{ -+ int ret = 0; -+ -+ TRACE_ENTER(QUIC_EV_CONN_LPKT, qc); -+ -+ switch (*pkt->token) { -+ case QUIC_TOKEN_FMT_RETRY: -+ ret = quic_retry_token_check(pkt, dgram, l, qc, odcid); -+ break; -+ case QUIC_TOKEN_FMT_NEW: -+ ret = quic_token_check(pkt, dgram, qc); -+ if (!ret) { -+ /* Fallback to a retry token in case of any error. */ -+ dgram->flags |= QUIC_DGRAM_FL_SEND_RETRY; -+ } -+ break; -+ default: -+ TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version); -+ break; -+ } -+ -+ if (!ret) -+ goto err; -+ -+ ret = 1; -+ leave: -+ TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc); -+ return ret; -+ err: -+ TRACE_DEVEL("leaving in error", QUIC_EV_CONN_LPKT, qc); -+ goto leave; -+} -+ - /* Find the associated connection to the packet or create a new one if - * this is an Initial packet. is the datagram containing the packet and - * is the listener instance on which it was received. -@@ -1645,22 +1687,38 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt, - } - - if (pkt->token_len) { -- /* Validate the token only when connection is unknown. */ -- if (!quic_retry_token_check(pkt, dgram, l, qc, &token_odcid)) -+ TRACE_PROTO("Initial with token", QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); -+ /* Validate the token, retry or not only when connection is unknown. */ -+ if (!quic_token_validate(pkt, dgram, l, qc, &token_odcid)) { -+ if (dgram->flags & QUIC_DGRAM_FL_SEND_RETRY) { -+ if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { -+ TRACE_ERROR("Error during Retry generation", -+ QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); -+ } -+ else -+ HA_ATOMIC_INC(&prx_counters->retry_sent); -+ -+ goto out; -+ } -+ - goto err; -+ } - } -- else if (!(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) && -- HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) { -- TRACE_PROTO("Initial without token, sending retry", -- QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); -- if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { -- TRACE_ERROR("Error during Retry generation", -+ else { -+ TRACE_PROTO("Initial without token", QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); -+ if (!(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) && -+ HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) { -+ TRACE_PROTO("Initial without token, sending retry", - QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); -+ if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) { -+ TRACE_ERROR("Error during Retry generation", -+ QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version); -+ goto out; -+ } -+ -+ HA_ATOMIC_INC(&prx_counters->retry_sent); - goto out; - } -- -- HA_ATOMIC_INC(&prx_counters->retry_sent); -- goto out; - } - - /* RFC 9000 7.2. Negotiating Connection IDs: -diff --git a/src/quic_sock.c b/src/quic_sock.c -index 7a18bac..6713bdb 100644 ---- a/src/quic_sock.c -+++ b/src/quic_sock.c -@@ -292,6 +292,7 @@ static int quic_lstnr_dgram_dispatch(unsigned char *pos, size_t len, void *owner - dgram->saddr = *saddr; - dgram->daddr = *daddr; - dgram->qc = NULL; -+ dgram->flags = 0; - - /* Attached datagram to its quic_receiver_buf and quic_dghdlrs. */ - LIST_APPEND(dgrams, &dgram->recv_list); -@@ -778,6 +779,7 @@ int qc_rcv_buf(struct quic_conn *qc) - new_dgram->saddr = saddr; - new_dgram->daddr = daddr; - new_dgram->qc = NULL; /* set later via quic_dgram_parse() */ -+ new_dgram->flags = 0; - - TRACE_DEVEL("read datagram", QUIC_EV_CONN_RCV, qc, new_dgram); - -diff --git a/src/quic_ssl.c b/src/quic_ssl.c -index 73bf8dc..b48494e 100644 ---- a/src/quic_ssl.c -+++ b/src/quic_ssl.c -@@ -354,6 +354,23 @@ static int ha_quic_add_handshake_data(SSL *ssl, enum ssl_encryption_level_t leve - - TRACE_ENTER(QUIC_EV_CONN_ADDDATA, qc); - -+ TRACE_PROTO("ha_quic_add_handshake_data() called", QUIC_EV_CONN_IO_CB, qc, NULL, ssl); -+ -+#ifdef HAVE_SSL_0RTT_QUIC -+ /* Detect asap if some 0-RTT data were accepted for this connection. -+ * If this is the case and no token was provided, interrupt the useless -+ * secrets derivations. A Retry packet must be sent, and this connection -+ * must be killed. -+ * Note that QUIC_FL_CONN_NO_TOKEN_RCVD is possibly set only for when 0-RTT is -+ * enabled for the connection. -+ */ -+ if ((qc->flags & QUIC_FL_CONN_NO_TOKEN_RCVD) && qc_ssl_eary_data_accepted(ssl)) { -+ TRACE_PROTO("connection to be killed", QUIC_EV_CONN_ADDDATA, qc); -+ qc->flags |= QUIC_FL_CONN_TO_KILL|QUIC_FL_CONN_SEND_RETRY; -+ goto leave; -+ } -+#endif -+ - if (qc->flags & QUIC_FL_CONN_TO_KILL) { - TRACE_PROTO("connection to be killed", QUIC_EV_CONN_ADDDATA, qc); - goto out; -@@ -528,9 +545,10 @@ int qc_ssl_provide_quic_data(struct ncbuf *ncbuf, - state = qc->state; - if (state < QUIC_HS_ST_COMPLETE) { - ssl_err = SSL_do_handshake(ctx->ssl); -+ TRACE_PROTO("SSL_do_handshake() called", QUIC_EV_CONN_IO_CB, qc, NULL, ctx->ssl); - - if (qc->flags & QUIC_FL_CONN_TO_KILL) { -- TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_IO_CB, qc); -+ TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_IO_CB, qc, &state, ctx->ssl); - goto leave; - } - --- -1.7.10.4 - diff --git a/CVE-2024-53008-1.patch b/CVE-2024-53008-1.patch deleted file mode 100644 index 0cb6f33ed616ab523cf173c85a6102a9660d5217..0000000000000000000000000000000000000000 --- a/CVE-2024-53008-1.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 87fefebfbe3df218103502046a0871b235a48087 Mon Sep 17 00:00:00 2001 -From: Amaury Denoyelle -Date: Fri, 28 Jun 2024 10:43:19 +0200 -Subject: [PATCH] BUG/MEDIUM: h3: ensure the ":method" pseudo header is totally - valid -Origin: https://github.com/haproxy/haproxy/commit/87fefebfbe3df218103502046a0871b235a48087 - -Ensure pseudo-header method is only constitued of valid characters -according to RFC 9110. If an invalid value is found, the request is -rejected and stream is resetted. - -Previously only characters forbidden in headers were rejected (NUL/CR/LF), -but this is insufficient for :method, where some other forbidden chars -might be used to trick a non-compliant backend server into seeing a -different path from the one seen by haproxy. Note that header injection -is not possible though. - -This must be backported up to 2.6. - -Many thanks to Yuki Mogi of FFRI Security Inc for the detailed report -that allowed to quicky spot, confirm and fix the problem. - -(cherry picked from commit 789d4abd7328f0a745d67698e89bbb888d4d9b2c) -Signed-off-by: Christopher Faulet -(cherry picked from commit 47d13c68cf198467a94e85a1caa44484a1e2e75c) -[cf: adapted] -Signed-off-by: Christopher Faulet ---- - include/haproxy/http.h | 15 +++++++++++++++ - src/h3.c | 8 ++++++++ - 2 files changed, 23 insertions(+) - -diff --git a/include/haproxy/http.h b/include/haproxy/http.h -index 299264051d28e..a297fa59b444a 100644 ---- a/include/haproxy/http.h -+++ b/include/haproxy/http.h -@@ -192,6 +192,21 @@ static inline int http_header_has_forbidden_char(const struct ist ist, const cha - return 0; - } - -+/* Check that method only contains token as required. -+ * See RFC 9110 9. Methods -+ */ -+static inline int http_method_has_forbidden_char(const struct ist ist) -+{ -+ const char *start = istptr(ist); -+ -+ do { -+ if (!HTTP_IS_TOKEN(*start)) -+ return 1; -+ start++; -+ } while (start < istend(ist)); -+ return 0; -+} -+ - /* Looks into for forbidden characters for :path values (0x00..0x1F, - * 0x20, 0x23), starting at pointer which must be within . - * Returns non-zero if such a character is found, 0 otherwise. When run on -diff --git a/src/h3.c b/src/h3.c -index 9e415b3b56303..4e21f6b92f535 100644 ---- a/src/h3.c -+++ b/src/h3.c -@@ -625,6 +625,14 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, - len = -1; - goto out; - } -+ -+ if (!istlen(list[hdr_idx].v) || http_method_has_forbidden_char(list[hdr_idx].v)) { -+ TRACE_ERROR("invalid method pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs); -+ h3s->err = H3_MESSAGE_ERROR; -+ len = -1; -+ goto out; -+ } -+ - meth = list[hdr_idx].v; - } - else if (isteq(list[hdr_idx].n, ist(":path"))) { diff --git a/CVE-2024-53008-2.patch b/CVE-2024-53008-2.patch deleted file mode 100644 index 55226bf20ee6a7b41cfed09a6ca1fc8a91407333..0000000000000000000000000000000000000000 --- a/CVE-2024-53008-2.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 6748a47819c263d4631187b6f121b5344ab50d57 Mon Sep 17 00:00:00 2001 -From: Amaury Denoyelle -Date: Fri, 28 Jun 2024 10:50:19 +0200 -Subject: [PATCH] BUG/MEDIUM: h3: ensure the ":scheme" pseudo header is totally - valid -Origin: https://github.com/haproxy/haproxy/commit/6748a47819c263d4631187b6f121b5344ab50d57 - -Ensure pseudo-header scheme is only constitued of valid characters -according to RFC 9110. If an invalid value is found, the request is -rejected and stream is resetted. - -It's the same as for previous commit "BUG/MEDIUM: h3: ensure the -":method" pseudo header is totally valid" except that this time it -applies to the ":scheme" pseudo header. - -This must be backported up to 2.6. - -(cherry picked from commit a3bed52d1f84ba36af66be4317a5f746d498bdf4) -Signed-off-by: Christopher Faulet -(cherry picked from commit 5ddc4004cb0c3c4ea4f4596577c85f004678e9c0) -[cf: adapted] -Signed-off-by: Christopher Faulet ---- - src/h3.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/src/h3.c b/src/h3.c -index 4e21f6b92f535..1984f984f7daf 100644 ---- a/src/h3.c -+++ b/src/h3.c -@@ -666,6 +666,14 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf, - len = -1; - goto out; - } -+ -+ if (!http_validate_scheme(list[hdr_idx].v)) { -+ TRACE_ERROR("invalid scheme pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs); -+ h3s->err = H3_MESSAGE_ERROR; -+ len = -1; -+ goto out; -+ } -+ - scheme = list[hdr_idx].v; - } - else if (isteq(list[hdr_idx].n, ist(":authority"))) { diff --git a/backport-BUG-MEDIUM-queue-Make-process_srv_queue-return-the-n.patch b/backport-BUG-MEDIUM-queue-Make-process_srv_queue-return-the-n.patch deleted file mode 100644 index 78e38f48a9104abf365081e66349ef79546e64ed..0000000000000000000000000000000000000000 --- a/backport-BUG-MEDIUM-queue-Make-process_srv_queue-return-the-n.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 4fb445fe5769172354d08f4a726f99e9815494c1 Mon Sep 17 00:00:00 2001 -From: Olivier Houchard -Date: Mon, 23 Dec 2024 14:17:25 +0000 -Subject: [PATCH] BUG/MEDIUM: queue: Make process_srv_queue return the number - of streams - -Make process_srv_queue() return the number of streams unqueued, as -pendconn_grab_from_px() did, as that number is used by -srv_update_status() to generate logs. - -This should be backported up to 2.6 with -111ea83ed4e13ac3ab028ed5e95201a1b4aa82b8 - -(cherry picked from commit 5b8899b6ccc7dab3a54a51dcb8ba1512bd0c886c) -Signed-off-by: Christopher Faulet -(cherry picked from commit 70588a16903002709cf3c84255ad8ded73f8e584) -Signed-off-by: Christopher Faulet -(cherry picked from commit 365378bfdf283650ce1ac152348ca59b6d4c32c1) -Signed-off-by: Christopher Faulet - -Conflict:NA -Reference:https://git.haproxy.org/?p=haproxy-2.9.git;a=patch;h=4fb445fe5769172354d08f4a726f99e9815494c1 ---- - include/haproxy/queue.h | 2 +- - src/queue.c | 3 ++- - src/server.c | 4 ++-- - 3 files changed, 5 insertions(+), 4 deletions(-) - -diff --git a/include/haproxy/queue.h b/include/haproxy/queue.h -index e4201fb..4896f71 100644 ---- a/include/haproxy/queue.h -+++ b/include/haproxy/queue.h -@@ -34,7 +34,7 @@ extern struct pool_head *pool_head_pendconn; - - struct pendconn *pendconn_add(struct stream *strm); - int pendconn_dequeue(struct stream *strm); --void process_srv_queue(struct server *s); -+int process_srv_queue(struct server *s); - unsigned int srv_dynamic_maxconn(const struct server *s); - int pendconn_redistribute(struct server *s); - int pendconn_grab_from_px(struct server *s); -diff --git a/src/queue.c b/src/queue.c -index 7555e2d..b93edf2 100644 ---- a/src/queue.c -+++ b/src/queue.c -@@ -354,7 +354,7 @@ static int pendconn_process_next_strm(struct server *srv, struct proxy *px, int - /* Manages a server's connection queue. This function will try to dequeue as - * many pending streams as possible, and wake them up. - */ --void process_srv_queue(struct server *s) -+int process_srv_queue(struct server *s) - { - struct server *ref = s->track ? s->track : s; - struct proxy *p = s->proxy; -@@ -413,6 +413,7 @@ void process_srv_queue(struct server *s) - if (p->lbprm.server_take_conn) - p->lbprm.server_take_conn(s); - } -+ return done; - } - - /* Adds the stream to the pending connection queue of server ->srv -diff --git a/src/server.c b/src/server.c -index 512fecd..cc2311a 100644 ---- a/src/server.c -+++ b/src/server.c -@@ -6012,7 +6012,7 @@ static int _srv_update_status_op(struct server *s, enum srv_op_st_chg_cause caus - /* check if we can handle some connections queued. - * We will take as many as we can handle. - */ -- process_srv_queue(s); -+ xferred = process_srv_queue(s); - - tmptrash = alloc_trash_chunk(); - if (tmptrash) { -@@ -6198,7 +6198,7 @@ static int _srv_update_status_adm(struct server *s, enum srv_adm_st_chg_cause ca - /* check if we can handle some connections queued. - * We will take as many as we can handle. - */ -- process_srv_queue(s); -+ xferred = process_srv_queue(s); - } - else if (s->next_admin & SRV_ADMF_MAINT) { - /* remaining in maintenance mode, let's inform precisely about the --- -1.7.10.4 - diff --git a/backport-BUG-MEDIUM-queues-Do-not-use-pendconn_grab_from_px.patch b/backport-BUG-MEDIUM-queues-Do-not-use-pendconn_grab_from_px.patch deleted file mode 100644 index 23d04d4fa51af3ba8b7bb9edbebba595c2920ae2..0000000000000000000000000000000000000000 --- a/backport-BUG-MEDIUM-queues-Do-not-use-pendconn_grab_from_px.patch +++ /dev/null @@ -1,89 +0,0 @@ -From e87aeeccfce15b27fb349c4a1f966c678d246417 Mon Sep 17 00:00:00 2001 -From: Olivier Houchard -Date: Tue, 17 Dec 2024 15:39:21 +0100 -Subject: [PATCH] BUG/MEDIUM: queues: Do not use pendconn_grab_from_px(). - -pendconn_grab_from_px() was called when a server was brought back up, to -get some streams waiting in the proxy's queue and get them to run on the -newly available server. It is very similar to process_srv_queue(), -except it only goes through the proxy's queue, which can be a problem, -because there is a small race condition that could lead us to add more -streams to the server queue just as it's going down. If that happens, -the server would just be ignored when back up by new streams, as its -queue is not empty, and it would never try to process its queue. -The other problem with pendconn_grab_from_px() is that it is very -liberal with how it dequeues streams, and it is not very good at -enforcing maxconn, it could lead to having 3*maxconn connections. -For both those reasons, just get rid of pendconn_grab_from_px(), and -just use process_srv_queue(). -Both problems are easy to reproduce, especially on a 64 threads machine, -set a maxconn to 100, inject in H2 with 1000 concurrent connections -containing up to 100 streams each, and after a few seconds/minutes the -max number of concurrent output streams will be much higher than -maxconn, and eventually the server will stop processing connections. - -It may be related to github issue #2744. Note that it doesn't totally -fix the problem, we can occasionally see a few more connections than -maxconn, but the max that have been observed is 4 more connections, we -no longer get multiple times maxconn. - -have more outgoing connections than maxconn, -This should be backported up to 2.6. - -(cherry picked from commit 111ea83ed4e13ac3ab028ed5e95201a1b4aa82b8) -Signed-off-by: Christopher Faulet -(cherry picked from commit ab4ff1b7a6c7685f28fbdea01b38caf7e816fddf) -Signed-off-by: Christopher Faulet -(cherry picked from commit b495692898072d6a843d36d4e66aae42e88a7c95) -Signed-off-by: Christopher Faulet - -Conflict:NA -Reference:https://git.haproxy.org/?p=haproxy-2.9.git;a=patch;h=e87aeeccfce15b27fb349c4a1f966c678d246417 ---- - src/server.c | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/src/server.c b/src/server.c -index 311b495..512fecd 100644 ---- a/src/server.c -+++ b/src/server.c -@@ -5305,7 +5305,7 @@ static struct task *server_warmup(struct task *t, void *context, unsigned int st - server_recalc_eweight(s, 1); - - /* probably that we can refill this server with a bit more connections */ -- pendconn_grab_from_px(s); -+ process_srv_queue(s); - - HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); - -@@ -6009,10 +6009,10 @@ static int _srv_update_status_op(struct server *s, enum srv_op_st_chg_cause caus - !(s->flags & SRV_F_BACKUP) && s->next_eweight) - srv_shutdown_backup_streams(s->proxy, SF_ERR_UP); - -- /* check if we can handle some connections queued at the proxy. We -- * will take as many as we can handle. -+ /* check if we can handle some connections queued. -+ * We will take as many as we can handle. - */ -- xferred = pendconn_grab_from_px(s); -+ process_srv_queue(s); - - tmptrash = alloc_trash_chunk(); - if (tmptrash) { -@@ -6195,10 +6195,10 @@ static int _srv_update_status_adm(struct server *s, enum srv_adm_st_chg_cause ca - !(s->flags & SRV_F_BACKUP) && s->next_eweight) - srv_shutdown_backup_streams(s->proxy, SF_ERR_UP); - -- /* check if we can handle some connections queued at the proxy. We -- * will take as many as we can handle. -+ /* check if we can handle some connections queued. -+ * We will take as many as we can handle. - */ -- xferred = pendconn_grab_from_px(s); -+ process_srv_queue(s); - } - else if (s->next_admin & SRV_ADMF_MAINT) { - /* remaining in maintenance mode, let's inform precisely about the --- -1.7.10.4 - diff --git a/backport-BUG-MEDIUM-queues-Make-sure-we-call-process_srv_queu.patch b/backport-BUG-MEDIUM-queues-Make-sure-we-call-process_srv_queu.patch deleted file mode 100644 index 4a8c404004b98eec59b44f27880a853237d8ce6e..0000000000000000000000000000000000000000 --- a/backport-BUG-MEDIUM-queues-Make-sure-we-call-process_srv_queu.patch +++ /dev/null @@ -1,50 +0,0 @@ -From f0c756518e9bfabfb317d22aa3416bc84eb543ba Mon Sep 17 00:00:00 2001 -From: Olivier Houchard -Date: Fri, 13 Dec 2024 17:11:05 +0000 -Subject: [PATCH] BUG/MEDIUM: queues: Make sure we call process_srv_queue() - when leaving - -In stream_free(), make sure we call process_srv_queue() each time we -call sess_change_server(), otherwise a server may end up not dequeuing -any stream when it could do so. In some extreme cases it could lead to -an infinite loop, as the server would appear to be available, as its -"served" parameter would be < maxconn, but would end up not being used, -as there are elements still in its queue. - -This should be backported up to 2.6. - -(cherry picked from commit dc9ce9c26469e00ab71fe6387dbd13010d4930f0) -Signed-off-by: Christopher Faulet -(cherry picked from commit 1385e4ca16b3797b0091a959b626935cd7f29b38) -Signed-off-by: Christopher Faulet -(cherry picked from commit 2de073ef00ee7d87aa82064dd2977645ec694730) -Signed-off-by: Christopher Faulet - -Conflict:NA -Reference:https://git.haproxy.org/?p=haproxy-2.9.git;a=patch;h=f0c756518e9bfabfb317d22aa3416bc84eb543ba ---- - src/stream.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/stream.c b/src/stream.c -index f4a3298..c42cf95 100644 ---- a/src/stream.c -+++ b/src/stream.c -@@ -625,11 +625,14 @@ void stream_free(struct stream *s) - } - - if (unlikely(s->srv_conn)) { -+ struct server *oldsrv = s->srv_conn; - /* the stream still has a reserved slot on a server, but - * it should normally be only the same as the one above, - * so this should not happen in fact. - */ - sess_change_server(s, NULL); -+ if (may_dequeue_tasks(oldsrv, s->be)) -+ process_srv_queue(oldsrv); - } - - /* We may still be present in the buffer wait queue */ --- -1.7.10.4 - diff --git a/backport-BUG-MEDIUM-server-addr-fix-tune.events.max-events-at.patch b/backport-BUG-MEDIUM-server-addr-fix-tune.events.max-events-at.patch deleted file mode 100644 index 1b41a7597d95cc8f128d485087f2aa9485bd2647..0000000000000000000000000000000000000000 --- a/backport-BUG-MEDIUM-server-addr-fix-tune.events.max-events-at.patch +++ /dev/null @@ -1,136 +0,0 @@ -From d9b6fa6b251b2db654ac42b623b86c06735978bd Mon Sep 17 00:00:00 2001 -From: Aurelien DARRAGON -Date: Tue, 6 Aug 2024 14:29:56 +0200 -Subject: [PATCH] BUG/MEDIUM: server/addr: fix tune.events.max-events-at-once - event miss and leak - -An issue has been introduced with cd99440 ("BUG/MAJOR: server/addr: fix -a race during server addr:svc_port updates"). - -Indeed, in the above commit we implemented the atomic_sync task which is -responsible for consuming pending server events to apply the changes -atomically. For now only server's addr updates are concerned. - -To prevent the task from causing contention, a budget was assigned to it. -It can be controlled with the global tunable -'tune.events.max-events-at-once': the task may not process more than this -number of events at once. - -However, a bug was introduced with this budget logic: each time the task -has to be interrupted because it runs out of budget, we reschedule the -task to finish where it left off, but the current event which was already -removed from the queue wasn't processed yet. This means that this pending -event (each tune.events.max-events-at-once) is effectively lost. - -When the atomic_sync task deals with large number of concurrent events, -this bug has 2 known consequences: first a server's addr/port update -will be lost every 'tune.events.max-events-at-once'. This can of course -cause reliability issues because if the event is not republished -periodically, the server could stay in a stale state for indefinite amount -of time. This is the case when the DNS server flaps for instance: some -servers may not come back UP after the incident as described in GH #2666. - -Another issue is that the lost event was not cleaned up, resulting in a -small memory leak. So in the end, it means that the bug is likely to -cause more and more degradation over time until haproxy is restarted. - -As a workaround, 'tune.events.max-events-at-once' may be set to the -maximum number of events expected per batch. Note however that this value -cannot exceed 10 000, otherwise it could cause the watchdog to trigger due -to the task being busy for too long and preventing other threads from -making any progress. Setting higher values may not be optimal for common -workloads so it should only be used to mitigate the bug while waiting for -this fix. - -Since tune.events.max-events-at-once defaults to 100, this bug only -affects configs that involve more than 100 servers whose addr:port -properties are likely to be updated at the same time (batched updates -from cli, lua, dns..) - -To fix the bug, we move the budget check after the current event is fully -handled. For that we went from a basic 'while' to 'do..while' loop as we -assume from the config that 'tune.events.max-events-at-once' cannot be 0. -While at it, we reschedule the task once thread isolation ends (it was not -required to perform the reschedule while under isolation) to give the hand -back faster to waiting threads. - -This patch should be backported up to 2.9 with cd99440. It should fix -GH #2666. - -(cherry picked from commit 8f1fd96d17588fb571959901bd20d4239b1a96af) -Signed-off-by: Christopher Faulet -(cherry picked from commit b2dabc930c0f6c231b0a757fd8e7e7b01818f398) -Signed-off-by: Christopher Faulet - -Conflict: NA -Reference: https://git.haproxy.org/?p=haproxy-2.9.git;a=commit;h=d9b6fa6b251b2db654ac42b623b86c06735978bd ---- - src/server.c | 34 ++++++++++++++++++---------------- - 1 file changed, 18 insertions(+), 16 deletions(-) - -diff --git a/src/server.c b/src/server.c -index fa5c4c704406b..5989a9373fada 100644 ---- a/src/server.c -+++ b/src/server.c -@@ -230,7 +230,11 @@ static struct task *server_atomic_sync(struct task *task, void *context, unsigne - struct event_hdl_async_event *event; - - /* check for new server events that we care about */ -- while ((event = event_hdl_async_equeue_pop(&server_atomic_sync_queue))) { -+ do { -+ event = event_hdl_async_equeue_pop(&server_atomic_sync_queue); -+ if (!event) -+ break; /* no events in queue */ -+ - if (event_hdl_sub_type_equal(event->type, EVENT_HDL_SUB_END)) { - /* ending event: no more events to come */ - event_hdl_async_free_event(event); -@@ -239,20 +243,6 @@ static struct task *server_atomic_sync(struct task *task, void *context, unsigne - break; - } - -- if (!remain) { -- /* STOP: we've already spent all our budget here, and -- * considering we possibly are under isolation, we cannot -- * keep blocking other threads any longer. -- * -- * Reschedule the task to finish where we left off if -- * there are remaining events in the queue. -- */ -- if (!event_hdl_async_equeue_isempty(&server_atomic_sync_queue)) -- task_wakeup(task, TASK_WOKEN_OTHER); -- break; -- } -- remain--; -- - /* new event to process */ - if (event_hdl_sub_type_equal(event->type, EVENT_HDL_SUB_SERVER_INETADDR)) { - struct sockaddr_storage new_addr; -@@ -313,7 +303,7 @@ static struct task *server_atomic_sync(struct task *task, void *context, unsigne - srv_set_addr_desc(srv, 1); - } - event_hdl_async_free_event(event); -- } -+ } while (--remain); // event_hdl_tune.max_events_at_once is expected to be > 0 - - /* some events possibly required thread_isolation: - * now that we are done, we must leave thread isolation before -@@ -322,6 +312,18 @@ static struct task *server_atomic_sync(struct task *task, void *context, unsigne - if (thread_isolated()) - thread_release(); - -+ if (!remain) { -+ /* we stopped because we've already spent all our budget here, -+ * and considering we possibly were under isolation, we cannot -+ * keep blocking other threads any longer. -+ * -+ * Reschedule the task to finish where we left off if -+ * there are remaining events in the queue. -+ */ -+ if (!event_hdl_async_equeue_isempty(&server_atomic_sync_queue)) -+ task_wakeup(task, TASK_WOKEN_OTHER); -+ } -+ - return task; - } - diff --git a/backport-BUG-MEDIUM-stream-Prevent-mux-upgrades-if-client-con.patch b/backport-BUG-MEDIUM-stream-Prevent-mux-upgrades-if-client-con.patch deleted file mode 100644 index 2f56503b662a8a0b826751858355d65aa3204dcc..0000000000000000000000000000000000000000 --- a/backport-BUG-MEDIUM-stream-Prevent-mux-upgrades-if-client-con.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 56fb102c0c6094792fd38455b38b88a94454e996 Mon Sep 17 00:00:00 2001 -From: Christopher Faulet -Date: Wed, 28 Aug 2024 15:42:22 +0200 -Subject: [PATCH] BUG/MEDIUM: stream: Prevent mux upgrades if client connection - is no longer ready - -If an early error occurred on the client connection, we must prevent any -multiplexer upgrades. Indeed, it is unexpected for a mux to be initialized -with no xprt. On a normal workflow it is impossible. So it is not an -issue. But if a mux upgrade is performed at the stream level, an early error -on the connection may have already been handled by the previous mux and the -connection may be already fully closed. If the mux upgrade is still -performed, a crash can be experienced. - -It is possible to have a crash with an implicit TCP>HTTP upgrade if there is no -data in the input buffer. But it is also possible to get a crash with an -explicit "switch-mode http" rule. - -It must be backported to all stable versions. In 2.2, the patch must be -applied directly in stream_set_backend() function. - -(cherry picked from commit e4812404c541018ba521abf6573be92553ba7c53) -Signed-off-by: Willy Tarreau -(cherry picked from commit 13437097c312e524a346b9016d8ab273374d2053) -Signed-off-by: Christopher Faulet - -Conflict: NA -Reference: https://github.com/haproxy/haproxy/commit/56fb102c0c6094792fd38455b38b88a94454e996 ---- - src/stream.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/stream.c b/src/stream.c -index e643a6db6a05..89b7c238fe48 100644 ---- a/src/stream.c -+++ b/src/stream.c -@@ -1488,6 +1488,10 @@ int stream_set_http_mode(struct stream *s, const struct mux_proto_list *mux_prot - return 0; - - conn = sc_conn(sc); -+ -+ if (!sc_conn_ready(sc)) -+ return 0; -+ - if (conn) { - se_have_more_data(s->scf->sedesc); - /* Make sure we're unsubscribed, the the new diff --git a/backport-BUG-MINOR-haproxy-only-tid-0-must-not-sleep-if-got-s.patch b/backport-BUG-MINOR-haproxy-only-tid-0-must-not-sleep-if-got-s.patch deleted file mode 100644 index 0598cfc268d195766dd053c13a6084f697f8d37c..0000000000000000000000000000000000000000 --- a/backport-BUG-MINOR-haproxy-only-tid-0-must-not-sleep-if-got-s.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 02819d2e36611d2e19c3ca084f75199c8c215067 Mon Sep 17 00:00:00 2001 -From: Valentine Krasnobaeva -Date: Mon, 6 May 2024 14:24:41 +0200 -Subject: [PATCH] BUG/MINOR: haproxy: only tid 0 must not sleep if got signal - -This patch fixes the commit eea152ee68 -("BUG/MINOR: signals/poller: ensure wakeup from signals"). - -There is some probability that run_poll_loop() becomes inifinite, if -TH_FL_SLEEPING is withdrawn from all threads in the second signal_queue_len -check, when a signal has received just after the first one. - -In such particular case, the 'wake' variable, which is used to terminate -thread's poll loop is never reset to 0. So, we never enter to the "stopping" -part of the run_poll_loop() and threads, except the one with id 0 (tid 0 -handles signals), will continue to call _do_poll() eternally and will never -sleep, as its TH_FL_SLEEPING flag was unset. - -This flag needs to be removed only for the tid 0, as it was done in the first -signal_queue_len check. - -This fixes an issue #2537 "infinite loop when shutting down". - -This fix must be backported in every stable version. - -(cherry picked from commit 4a9e3e102e192b9efd17e3241a6cc659afb7e7dc) -Signed-off-by: Amaury Denoyelle - -Conflict: NA -Reference: https://git.haproxy.org/?p=haproxy-2.9.git;a=commit;h=02819d2e36611d2e19c3ca084f75199c8c215067 ---- - src/haproxy.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/haproxy.c b/src/haproxy.c -index d0c3c4348ae12..8c20dfe22fa80 100644 ---- a/src/haproxy.c -+++ b/src/haproxy.c -@@ -3074,7 +3074,7 @@ void run_poll_loop() - if (thread_has_tasks()) { - activity[tid].wake_tasks++; - _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING); -- } else if (signal_queue_len) { -+ } else if (signal_queue_len && tid == 0) { - /* this check is required after setting TH_FL_SLEEPING to avoid - * a race with wakeup on signals using wake_threads() */ - _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING); diff --git a/backport-BUG-MINOR-server-fix-slowstart-behavior.patch b/backport-BUG-MINOR-server-fix-slowstart-behavior.patch deleted file mode 100644 index 06d9fcaa27a7d2b3be402d1846d0eb13c3efb2d9..0000000000000000000000000000000000000000 --- a/backport-BUG-MINOR-server-fix-slowstart-behavior.patch +++ /dev/null @@ -1,76 +0,0 @@ -From a6c0926ba1ca5eac00b0bcd25934f89b9693ddb0 Mon Sep 17 00:00:00 2001 -From: Damien Claisse -Date: Tue, 9 Apr 2024 15:37:07 +0000 -Subject: [PATCH] BUG/MINOR: server: fix slowstart behavior - -We observed that a dynamic server which health check is down for longer -than slowstart delay at startup doesn't trigger the warmup phase, it -receives full traffic immediately. This has been confirmed by checking -haproxy UI, weight is immediately the full one (e.g. 75/75), without any -throttle applied. Further tests showed that it was similar if it was in -maintenance, and even when entering a down or maintenance state after -being up. -Another issue is that if the server is down for less time than -slowstart, when it comes back up, it briefly has a much higher weight -than expected for a slowstart. - -An easy way to reproduce is to do the following: -- Add a server with e.g. a 20s slowstart and a weight of 10 in config - file -- Put it in maintenance using CLI (set server be1/srv1 state maint) -- Wait more than 20s, enable it again (set server be1/srv1 state ready) -- Observe UI, weight will show 10/10 immediately. -If server was down for less than 20s, you'd briefly see a weight and -throttle value that is inconsistent, e.g. 50% throttle value and a -weight of 5 if server comes back up after 10s before going back to -6% after a second or two. - -Code analysis shows that the logic in server_recalc_eweight stops the -warmup task by setting server's next state to SRV_ST_RUNNING if it -didn't change state for longer than the slowstart duration, regardless -of its current state. As a consequence, a server being down or disabled -for longer than the slowstart duration will never enter the warmup phase -when it will be up again. - -Regarding the weight when server comes back up, issue is that even if -the server is down, we still compute its next weight as if it was up, -hence when it comes back up, it can briefly have a much higher weight -than expected during slowstart, until the warmup task is called again -after last_change is updated. - -This patch aims to fix both issues. - -(cherry picked from commit 0797e05d9f0577d9239d4265667ea536a2439db0) -Signed-off-by: Christopher Faulet - -Conflict: NA -Reference:https://github.com/haproxy/haproxy/commit/a6c0926ba1ca5eac00b0bcd25934f89b9693ddb0 ---- - src/server.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/server.c b/src/server.c -index 7655b3315f4ee..fc7fde608e5ea 100644 ---- a/src/server.c -+++ b/src/server.c -@@ -2291,15 +2291,17 @@ void server_recalc_eweight(struct server *sv, int must_update) - unsigned w; - - if (ns_to_sec(now_ns) < sv->last_change || ns_to_sec(now_ns) >= sv->last_change + sv->slowstart) { -- /* go to full throttle if the slowstart interval is reached */ -- if (sv->next_state == SRV_ST_STARTING) -+ /* go to full throttle if the slowstart interval is reached unless server is currently down */ -+ if ((sv->cur_state != SRV_ST_STOPPED) && (sv->next_state == SRV_ST_STARTING)) - sv->next_state = SRV_ST_RUNNING; - } - - /* We must take care of not pushing the server to full throttle during slow starts. - * It must also start immediately, at least at the minimal step when leaving maintenance. - */ -- if ((sv->next_state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN)) -+ if ((sv->cur_state == SRV_ST_STOPPED) && (sv->next_state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN)) -+ w = 1; -+ else if ((sv->next_state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN)) - w = (px->lbprm.wdiv * (ns_to_sec(now_ns) - sv->last_change) + sv->slowstart) / sv->slowstart; - else - w = px->lbprm.wdiv; diff --git a/backport-BUG-MINOR-server-source-interface-ignored-from-defau.patch b/backport-BUG-MINOR-server-source-interface-ignored-from-defau.patch deleted file mode 100644 index cc0b736086ce8f107d251f1598e4c77046468af4..0000000000000000000000000000000000000000 --- a/backport-BUG-MINOR-server-source-interface-ignored-from-defau.patch +++ /dev/null @@ -1,45 +0,0 @@ -From ada8c0e37df568c58e3a328c171d6f27bcfbe652 Mon Sep 17 00:00:00 2001 -From: Aurelien DARRAGON -Date: Tue, 26 Mar 2024 10:42:48 +0100 -Subject: [PATCH] BUG/MINOR: server: 'source' interface ignored from - 'default-server' directive - -Sebastien Gross reported that 'interface' keyword ('source' subargument) -is silently ignored when used from 'default-server' directive despite the -documentation implicitly stating that the keyword should be supported -there. - -When support for 'source' keyword was added to 'default-server' directive -in dba97077 ("MINOR: server: Make 'default-server' support 'source' -keyword."), we properly duplicated the conn iface_name from the default- -server but we forgot to copy the conn iface_len which must be set as well -since it is used as setsockopt()'s 'optlen' argument in -tcp_connect_server(). - -It should be backported to all stable versions. - -(cherry picked from commit bd98db50785b6cef946d38715b48f72e7ca73a59) -Signed-off-by: Christopher Faulet - -Conflict: NA -Reference: https://git.haproxy.org/?p=haproxy-2.9.git;a=patch;h=ada8c0e37df568c58e3a328c171d6f27bcfbe652 ---- - src/server.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/server.c b/src/server.c -index ef70a8f27583..1d88e4a3df1e 100644 ---- a/src/server.c -+++ b/src/server.c -@@ -2507,8 +2507,10 @@ static void srv_conn_src_cpy(struct server *srv, const struct server *src) - srv->conn_src.bind_hdr_occ = src->conn_src.bind_hdr_occ; - srv->conn_src.tproxy_addr = src->conn_src.tproxy_addr; - #endif -- if (src->conn_src.iface_name != NULL) -+ if (src->conn_src.iface_name != NULL) { - srv->conn_src.iface_name = strdup(src->conn_src.iface_name); -+ srv->conn_src.iface_len = src->conn_src.iface_len; -+ } - } - - /* diff --git a/backport-CVE-2025-32464.patch b/backport-CVE-2025-32464.patch deleted file mode 100644 index 8280bad621e069bba58ef36fb5a1bc25d890787e..0000000000000000000000000000000000000000 --- a/backport-CVE-2025-32464.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 3e3b9eebf871510aee36c3a3336faac2f38c9559 Mon Sep 17 00:00:00 2001 -From: Willy Tarreau -Date: Mon, 7 Apr 2025 15:30:43 +0200 -Subject: [PATCH] BUG/MEDIUM: sample: fix risk of overflow when replacing - multiple regex back-refs - -Aleandro Prudenzano of Doyensec and Edoardo Geraci of Codean Labs -reported a bug in sample_conv_regsub(), which can cause replacements -of multiple back-references to overflow the temporary trash buffer. - -The problem happens when doing "regsub(match,replacement,g)": we're -replacing every occurrence of "match" with "replacement" in the input -sample, which requires a length check. For this, a max is applied, so -that a replacement may not use more than the remaining length in the -buffer. However, the length check is made on the replaced pattern and -not on the temporary buffer used to carry the new string. This results -in the remaining size to be usable for each input match, which can go -beyond the temporary buffer size if more than one occurrence has to be -replaced with something that's larger than the remaining room. - -The fix proposed by Aleandro and Edoardo is the correct one (check on -"trash" not "output"), and is the one implemented in this patch. - -While it is very unlikely that a config will replace multiple short -patterns each with a larger one in a request, this possibility cannot -be entirely ruled out (e.g. mask a known, short IP address using -"XXX.XXX.XXX.XXX"). However when this happens, the replacement pattern -will be static, and not be user-controlled, which is why this patch is -marked as medium. - -The bug was introduced in 2.2 with commit 07e1e3c93e ("MINOR: sample: -regsub now supports backreferences"), so it must be backported to all -versions. - -Special thanks go to Aleandro and Edoardo for reporting this bug with -a simple reproducer and a fix. - -Conflict: NA -Reference: https://github.com/haproxy/haproxy/commit/3e3b9eebf871510aee36c3a3336faac2f38c9559 ---- - src/sample.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/sample.c b/src/sample.c -index 1e2ff7d2ee8e8..980c27cb6a507 100644 ---- a/src/sample.c -+++ b/src/sample.c -@@ -3168,7 +3168,7 @@ static int sample_conv_regsub(const struct arg *arg_p, struct sample *smp, void - output->data = exp_replace(output->area, output->size, start, arg_p[1].data.str.area, pmatch); - - /* replace the matching part */ -- max = output->size - output->data; -+ max = trash->size - trash->data; - if (max) { - if (max > output->data) - max = output->data; diff --git a/haproxy-2.9.5.tar.gz b/haproxy-3.0.11.tar.gz similarity index 38% rename from haproxy-2.9.5.tar.gz rename to haproxy-3.0.11.tar.gz index bff23afaf1ce201341bdd7d32d1c2db77dcb0457..d7cccd8a68d0151e28b58e145cbb32889a905059 100644 Binary files a/haproxy-2.9.5.tar.gz and b/haproxy-3.0.11.tar.gz differ diff --git a/haproxy.spec b/haproxy.spec index d0fecc1b2481dc1f179e9d142c81689e793f891f..7aa76b86f51ecc4315adab9670ed133322e7efc0 100644 --- a/haproxy.spec +++ b/haproxy.spec @@ -4,34 +4,21 @@ %global _hardened_build 1 Name: haproxy -Version: 2.9.5 -Release: 12 +Version: 3.0.11 +Release: 1 Summary: The Reliable, High Performance TCP/HTTP Load Balancer -License: GPLv2+ +License: GPL-2.0-or-later URL: https://www.haproxy.org/ -Source0: https://www.haproxy.org/download/2.9/src/%{name}-%{version}.tar.gz +Source0: https://www.haproxy.org/download/3.0/src/%{name}-%{version}.tar.gz Source1: %{name}.service Source2: %{name}.cfg Source3: %{name}.logrotate Source4: %{name}.sysconfig -Patch1: backport-BUG-MINOR-server-source-interface-ignored-from-defau.patch -Patch2: Backport-CVE-2024-45506-BUG-MAJOR-mux-h2-always.patch -Patch3: CVE-2024-49214.patch -Patch4: backport-BUG-MEDIUM-stream-Prevent-mux-upgrades-if-client-con.patch -Patch5: CVE-2024-53008-1.patch -Patch6: CVE-2024-53008-2.patch -Patch7: backport-BUG-MEDIUM-queues-Do-not-use-pendconn_grab_from_px.patch -Patch8: backport-BUG-MEDIUM-queues-Make-sure-we-call-process_srv_queu.patch -Patch9: backport-BUG-MEDIUM-queue-Make-process_srv_queue-return-the-n.patch -Patch10: backport-CVE-2025-32464.patch -Patch11: backport-BUG-MINOR-server-fix-slowstart-behavior.patch -Patch12: backport-BUG-MEDIUM-server-addr-fix-tune.events.max-events-at.patch -Patch13: backport-BUG-MINOR-haproxy-only-tid-0-must-not-sleep-if-got-s.patch -Patch14: backport-CVE-2025-11230.patch - -BuildRequires: gcc lua-devel pcre2-devel openssl-devel systemd-devel systemd libatomic +Patch1: backport-CVE-2025-11230.patch + +BuildRequires: gcc lua-devel pcre2-devel openssl-devel systemd-devel systemd libatomic libxcrypt-devel Requires(pre): shadow-utils %{?systemd_requires} @@ -43,19 +30,16 @@ web sites and powers quite a number of the world's most visited ones. %prep %autosetup -n %{name}-%{version} -p1 -%build -%if "%toolchain" == "clang" - %global make_opts CC=clang -%endif -%make_build %{?make_opts} CPU="generic" TARGET="linux-glibc" USE_OPENSSL=1 USE_PCRE2=1 USE_SLZ=1 \ +%build +%make_build CC="%{__cc}" CXX="%{__cxx}" CPU="generic" TARGET="linux-glibc" USE_OPENSSL=1 USE_PCRE2=1 USE_SLZ=1 \ USE_LUA=1 USE_CRYPT_H=1 USE_SYSTEMD=1 USE_LINUX_TPROXY=1 USE_GETADDRINFO=1 USE_PROMEX=1 DEFINE=-DMAX_SESS_STKCTR=12 \ - ADDINC="%{build_cflags}" ADDLIB="%{build_ldflags}" + CFLAGS="%{build_cflags}" ARCH_FLAGS="%{build_cflags}" LDFLAGS="%{build_ldflags}" -%make_build %{?make_opts} admin/halog/halog ADDINC="%{build_cflags}" ADDLIB="%{build_ldflags}" +%make_build CC="%{__cc}" CXX="%{__cxx}" admin/halog/halog ARCH_FLAGS="%{build_cflags}" LDFLAGS="%{build_ldflags}" pushd admin/iprange -%make_build %{?make_opts} OPTIMIZE="%{build_cflags}" LDFLAGS="%{build_ldflags}" +%make_build CC="%{__cc}" OPTIMIZE="%{build_cflags}" LDFLAGS="%{build_ldflags}" popd %install @@ -112,7 +96,6 @@ exit 0 %systemd_postun_with_restart %{name}.service %files -%defattr(-,root,root) %license LICENSE %dir %{_sysconfdir}/haproxy %config(noreplace) %{_sysconfdir}/haproxy/%{name}.cfg @@ -129,11 +112,16 @@ exit 0 %{_datadir}/haproxy/* %files help -%defattr(-,root,root) %doc doc/* examples/* CHANGELOG README VERSION %{_mandir}/man1/* %changelog +* Tue Oct 21 2025 xinghe - 3.0.11-1 +- Type:requirement +- ID:NA +- SUG:NA +- DESC:Update to 3.0.11 + * Thu Oct 09 2025 xinghe - 2.9.5-12 - Type:cves - CVE:CVE-2025-11230