Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
8591a94bd7
!152 Fix CVE-2024-53008
From: @wk333 
Reviewed-by: @wang--ge 
Signed-off-by: @wang--ge
2024-12-10 06:17:51 +00:00
wk333
e053271e11 Fix CVE-2024-53008 2024-12-10 10:27:43 +08:00
openeuler-ci-bot
9ad5949af4
!149 backport upstream patches
From: @xinghe_1 
Reviewed-by: @wang--ge 
Signed-off-by: @wang--ge
2024-11-21 07:51:48 +00:00
xh
fec3d9e6d6 backport upstream patches 2024-11-21 03:39:21 +00:00
openeuler-ci-bot
8e5c01df7f
!143 [sync] PR-142: Fix CVE-2024-49214
From: @openeuler-sync-bot 
Reviewed-by: @wang--ge 
Signed-off-by: @wang--ge
2024-10-14 09:08:58 +00:00
starlet-dx
86c1532116 Fix CVE-2024-49214
(cherry picked from commit aec3b76ff86c2701b58145801a9a8b946a0e93b7)
2024-10-14 16:29:17 +08:00
openeuler-ci-bot
d8fd92498f
!133 fix CVE-2024-45506
From: @yinyongkang 
Reviewed-by: @wang--ge 
Signed-off-by: @wang--ge
2024-09-09 08:03:54 +00:00
yinyongkang
3eefa87285 fix CVE-2024-45506 2024-09-04 10:58:22 +08:00
openeuler-ci-bot
2d3efd60c1
!129 [sync] PR-126: backport upstream patches
From: @openeuler-sync-bot 
Reviewed-by: @wu-leilei 
Signed-off-by: @wu-leilei
2024-06-27 08:50:04 +00:00
xh
fdf30b4e39 backport upstream patches
(cherry picked from commit dd6bca601df69630b08394741d61a08a11f9dfdc)
2024-06-27 16:20:12 +08:00
7 changed files with 794 additions and 1 deletions

View File

@ -0,0 +1,91 @@
From c725db17e8416ffb3c1537aea756356228ce5e3c Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
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 <w@1wt.eu>
---
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

458
CVE-2024-49214.patch Normal file
View 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
View 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
View 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"))) {

View File

@ -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

View File

@ -0,0 +1,45 @@
From ada8c0e37df568c58e3a328c171d6f27bcfbe652 Mon Sep 17 00:00:00 2001
From: Aurelien DARRAGON <adarragon@haproxy.com>
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 <cfaulet@haproxy.com>
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;
+ }
}
/*

View File

@ -5,7 +5,7 @@
Name: haproxy
Version: 2.9.5
Release: 2
Release: 7
Summary: The Reliable, High Performance TCP/HTTP Load Balancer
License: GPLv2+
@ -16,6 +16,12 @@ 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
BuildRequires: gcc lua-devel pcre2-devel openssl-devel systemd-devel systemd libatomic
Requires(pre): shadow-utils
@ -120,6 +126,30 @@ exit 0
%{_mandir}/man1/*
%changelog
* 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
- Type:CVE
- CVE:CVE-2024-45506
- SUG:NA
- DESC:fix CVE-2024-45506
* Mon Jun 24 2024 xinghe <xinghe2@h-partners.com> - 2.9.5-3
- Type:bugfix
- CVE:NA
- SUG:NA
- DESC:server: 'source' interface ignored from 'default-server' directive
* Thu Feb 22 2024 luofng <luofeng13@huawei.com> - 2.9.5-2
- Type:enhencement
- CVE:NA