Compare commits
10 Commits
fade7c259a
...
d6dca68099
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6dca68099 | ||
|
|
3d1a3148ca | ||
|
|
d5d68cf310 | ||
|
|
25cd8bcf22 | ||
|
|
a384b803bc | ||
|
|
11d681b403 | ||
|
|
a77f1e6fd2 | ||
|
|
5c2977b534 | ||
|
|
4a562f7c34 | ||
|
|
aec3b76ff8 |
458
CVE-2024-49214.patch
Normal file
458
CVE-2024-49214.patch
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
From fe5685af820ae62fe5b0d80b5ed7a2ffc41a036f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Frederic Lecaille <flecaille@haproxy.com>
|
||||||
|
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 <flecaille@haproxy.com>
|
||||||
|
(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 <w@1wt.eu>
|
||||||
|
---
|
||||||
|
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 <haproxy/quic_cid-t.h>
|
||||||
|
+
|
||||||
|
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 <dgram_list>. */
|
||||||
|
struct mt_list handler_list; /* elem to quic_dghdlr <dgrams>. */
|
||||||
|
+
|
||||||
|
+ 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 <haproxy/quic_sock.h>
|
||||||
|
#include <haproxy/quic_stats.h>
|
||||||
|
#include <haproxy/quic_stream.h>
|
||||||
|
+#include <haproxy/quic_token.h>
|
||||||
|
#include <haproxy/quic_tp.h>
|
||||||
|
#include <haproxy/quic_trace.h>
|
||||||
|
#include <haproxy/quic_tx.h>
|
||||||
|
@@ -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 <max> 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).
|
||||||
|
* <dcid> is the destination connection ID, <scid> is the source connection ID.
|
||||||
|
* This latter <scid> CID as the same value on the wire as the one for <conn_id>
|
||||||
|
- * 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
|
||||||
|
* <conn_id> in the CIDs tree for this connection (qc->cids).
|
||||||
|
- * <token> is the token found to be used for this connection with <token_len> as
|
||||||
|
- * length. Endpoints addresses are specified via <local_addr> and <peer_addr>.
|
||||||
|
+ * <token> is a boolean denoting if a token was received for this connection
|
||||||
|
+ * from an Initial packet.
|
||||||
|
+ * <token_odcid> 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 <local_addr> and <peer_addr>.
|
||||||
|
* 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 <haproxy/quic_stream.h>
|
||||||
|
#include <haproxy/quic_ssl.h>
|
||||||
|
#include <haproxy/quic_tls.h>
|
||||||
|
+#include <haproxy/quic_token.h>
|
||||||
|
#include <haproxy/quic_trace.h>
|
||||||
|
#include <haproxy/quic_tx.h>
|
||||||
|
#include <haproxy/ssl_sock.h>
|
||||||
|
@@ -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
|
||||||
|
+ * <pkt> RX packet from <dgram> 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 <pkt> or create a new one if
|
||||||
|
* this is an Initial packet. <dgram> is the datagram containing the packet and
|
||||||
|
* <l> 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
|
||||||
|
|
||||||
77
CVE-2024-53008-1.patch
Normal file
77
CVE-2024-53008-1.patch
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
From 87fefebfbe3df218103502046a0871b235a48087 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
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 <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit 47d13c68cf198467a94e85a1caa44484a1e2e75c)
|
||||||
|
[cf: adapted]
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
---
|
||||||
|
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 <ist> for forbidden characters for :path values (0x00..0x1F,
|
||||||
|
* 0x20, 0x23), starting at pointer <start> which must be within <ist>.
|
||||||
|
* 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"))) {
|
||||||
45
CVE-2024-53008-2.patch
Normal file
45
CVE-2024-53008-2.patch
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
From 6748a47819c263d4631187b6f121b5344ab50d57 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
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 <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit 5ddc4004cb0c3c4ea4f4596577c85f004678e9c0)
|
||||||
|
[cf: adapted]
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
---
|
||||||
|
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"))) {
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
From 4fb445fe5769172354d08f4a726f99e9815494c1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Olivier Houchard <ohouchard@haproxy.com>
|
||||||
|
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 <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit 70588a16903002709cf3c84255ad8ded73f8e584)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit 365378bfdf283650ce1ac152348ca59b6d4c32c1)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
|
||||||
|
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 <strm> to the pending connection queue of server <strm>->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
|
||||||
|
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
From e87aeeccfce15b27fb349c4a1f966c678d246417 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Olivier Houchard <ohouchard@haproxy.com>
|
||||||
|
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 <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit ab4ff1b7a6c7685f28fbdea01b38caf7e816fddf)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit b495692898072d6a843d36d4e66aae42e88a7c95)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
From f0c756518e9bfabfb317d22aa3416bc84eb543ba Mon Sep 17 00:00:00 2001
|
||||||
|
From: Olivier Houchard <ohouchard@haproxy.com>
|
||||||
|
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 <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit 1385e4ca16b3797b0091a959b626935cd7f29b38)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
(cherry picked from commit 2de073ef00ee7d87aa82064dd2977645ec694730)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
From 56fb102c0c6094792fd38455b38b88a94454e996 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
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 <w@1wt.eu>
|
||||||
|
(cherry picked from commit 13437097c312e524a346b9016d8ab273374d2053)
|
||||||
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
|
||||||
|
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
|
||||||
56
backport-CVE-2025-32464.patch
Normal file
56
backport-CVE-2025-32464.patch
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
From 3e3b9eebf871510aee36c3a3336faac2f38c9559 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Willy Tarreau <w@1wt.eu>
|
||||||
|
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;
|
||||||
36
haproxy.spec
36
haproxy.spec
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
Name: haproxy
|
Name: haproxy
|
||||||
Version: 2.9.5
|
Version: 2.9.5
|
||||||
Release: 4
|
Release: 9
|
||||||
Summary: The Reliable, High Performance TCP/HTTP Load Balancer
|
Summary: The Reliable, High Performance TCP/HTTP Load Balancer
|
||||||
|
|
||||||
License: GPLv2+
|
License: GPLv2+
|
||||||
@ -18,6 +18,14 @@ Source4: %{name}.sysconfig
|
|||||||
|
|
||||||
Patch1: backport-BUG-MINOR-server-source-interface-ignored-from-defau.patch
|
Patch1: backport-BUG-MINOR-server-source-interface-ignored-from-defau.patch
|
||||||
Patch2: Backport-CVE-2024-45506-BUG-MAJOR-mux-h2-always.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
|
||||||
|
|
||||||
BuildRequires: gcc lua-devel pcre2-devel openssl-devel systemd-devel systemd libatomic
|
BuildRequires: gcc lua-devel pcre2-devel openssl-devel systemd-devel systemd libatomic
|
||||||
Requires(pre): shadow-utils
|
Requires(pre): shadow-utils
|
||||||
@ -122,6 +130,32 @@ exit 0
|
|||||||
%{_mandir}/man1/*
|
%{_mandir}/man1/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Apr 29 2025 xinghe <xinghe2@h-partners.com> - 2.9.5-9
|
||||||
|
- Type:cves
|
||||||
|
- CVE:CVE-2025-32464
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:fix CVE-2025-32464
|
||||||
|
|
||||||
|
* Mon Mar 17 2025 yanglu <yanglu72@h-partners.com> - 2.9.5-8
|
||||||
|
- Type:bugfix
|
||||||
|
- CVE:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:queues:Do not use pendconn_grab_from_px
|
||||||
|
queues:Make sure we call process_srv_queue when leaving
|
||||||
|
queue:Make process_srv_queue return the number of streams
|
||||||
|
|
||||||
|
* Tue Dec 10 2024 wangkai <13474090681@163.com> - 2.9.5-7
|
||||||
|
- Fix CVE-2024-53008
|
||||||
|
|
||||||
|
* Thu Nov 21 2024 xinghe <xinghe2@h-partners.com> - 2.9.5-6
|
||||||
|
- Type:bugfix
|
||||||
|
- CVE:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:stream: Prevent mux upgrades if client connection is no longer ready
|
||||||
|
|
||||||
|
* Mon Oct 14 2024 yaoxin <yao_xin001@hoperun.com> - 2.9.5-5
|
||||||
|
- Fix CVE-2024-49214
|
||||||
|
|
||||||
* Wed Sep 04 2024 yinyongkang <yinyongkang@kylinos.cn> - 2.9.5-4
|
* Wed Sep 04 2024 yinyongkang <yinyongkang@kylinos.cn> - 2.9.5-4
|
||||||
- Type:CVE
|
- Type:CVE
|
||||||
- CVE:CVE-2024-45506
|
- CVE:CVE-2024-45506
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user