Fix CVE-2024-53008
(cherry picked from commit c8f478dd041baad66798d303f76d5546a312ed7d)
This commit is contained in:
parent
92cae65eb5
commit
8279e567c8
518
CVE-2024-53008.patch
Normal file
518
CVE-2024-53008.patch
Normal file
@ -0,0 +1,518 @@
|
||||
Orgin:
|
||||
pre patch:
|
||||
https://github.com/haproxy/haproxy/commit/1e4d26aee5e9c846c63b6f2955966826b7a488d0
|
||||
https://github.com/haproxy/haproxy/commit/dec64351957e10cbcd67d9bd1755a406c1dd9eff
|
||||
https://github.com/haproxy/haproxy/commit/434f74c8128337146f6828da731b9c9d4fb0499e
|
||||
fix patch:
|
||||
https://github.com/haproxy/haproxy/commit/fa8b221756076186315b6bbf17ef697ec1ef5695
|
||||
https://github.com/haproxy/haproxy/commit/94d74d24ec9c3710334ab2239b1996faab3ad01e
|
||||
|
||||
From 1e4d26aee5e9c846c63b6f2955966826b7a488d0 Mon Sep 17 00:00:00 2001
|
||||
From: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||
Date: Wed, 7 Dec 2022 14:33:26 +0100
|
||||
Subject: [PATCH] BUG/MEDIUM: h3: reject request with invalid pseudo header
|
||||
|
||||
RFC 9114 dictates several requirements for pseudo header usage in H3
|
||||
request. Previously only minimal checks were implemented. Enforce all
|
||||
the following requirements with this patch :
|
||||
* reject request with undefined or invalid pseudo header
|
||||
* reject request with duplicated pseudo header
|
||||
* reject non-CONNECT request with missing mandatory pseudo header
|
||||
* reject request with pseudo header after standard ones
|
||||
|
||||
For the moment, this kind of errors triggers a connection close. In the
|
||||
future, it should be handled only with a stream reset. To reduce
|
||||
backport surface, this will be implemented in another commit.
|
||||
|
||||
This must be backported up to 2.6.
|
||||
|
||||
From dec64351957e10cbcd67d9bd1755a406c1dd9eff Mon Sep 17 00:00:00 2001
|
||||
From: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||
Date: Thu, 8 Dec 2022 16:54:42 +0100
|
||||
Subject: [PATCH] BUG/MEDIUM: h3: parse content-length and reject invalid
|
||||
messages
|
||||
|
||||
Ensure that if a request contains a content-length header it matches
|
||||
with the total size of following DATA frames. This is conformance with
|
||||
HTTP/3 RFC 9114.
|
||||
|
||||
For the moment, this kind of errors triggers a connection close. In the
|
||||
future, it should be handled only with a stream reset. To reduce
|
||||
backport surface, this will be implemented in another commit.
|
||||
|
||||
This must be backported up to 2.6. It relies on the previous commit :
|
||||
MINOR: http: extract content-length parsing from H2
|
||||
|
||||
From 434f74c8128337146f6828da731b9c9d4fb0499e Mon Sep 17 00:00:00 2001
|
||||
From: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||
Date: Thu, 15 Dec 2022 10:53:55 +0100
|
||||
Subject: [PATCH] BUG/MINOR: h3: fix memleak on HEADERS parsing failure
|
||||
|
||||
If an error is triggered on H3 HEADERS parsing, the allocated buffer for
|
||||
HTX data is not freed.
|
||||
|
||||
To prevent this memleak, all return path have been centralized using
|
||||
goto statements.
|
||||
|
||||
Also, as a small bonus, offer_buffers() is not called anymore if buffer
|
||||
is not freed because sedesc has taken it. However this change has
|
||||
probably no noticeable effect as dynamic buffers management is not
|
||||
functional currently.
|
||||
|
||||
This should be backported up to 2.6.
|
||||
|
||||
From fa8b221756076186315b6bbf17ef697ec1ef5695 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
|
||||
|
||||
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>
|
||||
(cherry picked from commit 87fefebfbe3df218103502046a0871b235a48087)
|
||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||
(cherry picked from commit 94d305eaffc83dff3f59f5c2a3fbeb4710efa39a)
|
||||
[cf: There is no err field in h3s]
|
||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||
|
||||
From 94d74d24ec9c3710334ab2239b1996faab3ad01e 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
|
||||
|
||||
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>
|
||||
(cherry picked from commit 6748a47819c263d4631187b6f121b5344ab50d57)
|
||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||
(cherry picked from commit 56ab17d34a32d9c15558c2c2d17b743e6d679cbd)
|
||||
[cf: There is no err field in h3s]
|
||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
||||
|
||||
---
|
||||
include/haproxy/http.h | 14 +++
|
||||
src/h3.c | 225 ++++++++++++++++++++++++++++++++++++-----
|
||||
2 files changed, 212 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/include/haproxy/http.h b/include/haproxy/http.h
|
||||
index ee2f922..711883f 100644
|
||||
--- a/include/haproxy/http.h
|
||||
+++ b/include/haproxy/http.h
|
||||
@@ -171,6 +171,20 @@ static inline struct http_uri_parser http_uri_parser_init(const struct ist uri)
|
||||
return parser;
|
||||
}
|
||||
|
||||
+/* 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;
|
||||
+}
|
||||
+
|
||||
#endif /* _HAPROXY_HTTP_H */
|
||||
|
||||
/*
|
||||
diff --git a/src/h3.c b/src/h3.c
|
||||
index 8f96418..ef84f27 100644
|
||||
--- a/src/h3.c
|
||||
+++ b/src/h3.c
|
||||
@@ -133,6 +133,7 @@ DECLARE_STATIC_POOL(pool_head_h3c, "h3c", sizeof(struct h3c));
|
||||
|
||||
#define H3_SF_UNI_INIT 0x00000001 /* stream type not parsed for unidirectional stream */
|
||||
#define H3_SF_UNI_NO_H3 0x00000002 /* unidirectional stream does not carry H3 frames */
|
||||
+#define H3_SF_HAVE_CLEN 0x00000004 /* content-length header is present */
|
||||
|
||||
struct h3s {
|
||||
struct h3c *h3c;
|
||||
@@ -142,6 +143,9 @@ struct h3s {
|
||||
int demux_frame_len;
|
||||
int demux_frame_type;
|
||||
|
||||
+ unsigned long long body_len; /* known request body length from content-length header if present */
|
||||
+ unsigned long long data_len; /* total length of all parsed DATA */
|
||||
+
|
||||
int flags;
|
||||
};
|
||||
|
||||
@@ -325,6 +329,47 @@ static int h3_is_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype)
|
||||
}
|
||||
}
|
||||
|
||||
+/* Check from stream <qcs> that length of all DATA frames does not exceed with
|
||||
+ * a previously parsed content-length header. <fin> must be set for the last
|
||||
+ * data of the stream so that length of DATA frames must be equal to the
|
||||
+ * content-length.
|
||||
+ *
|
||||
+ * This must only be called for a stream with H3_SF_HAVE_CLEN flag.
|
||||
+ *
|
||||
+ * Return 0 on valid else non-zero.
|
||||
+ */
|
||||
+static int h3_check_body_size(struct qcs *qcs, int fin)
|
||||
+{
|
||||
+ struct h3s *h3s = qcs->ctx;
|
||||
+ int ret = 0;
|
||||
+ TRACE_ENTER(H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
||||
+
|
||||
+ /* Reserved for streams with a previously parsed content-length header. */
|
||||
+ BUG_ON(!(h3s->flags & H3_SF_HAVE_CLEN));
|
||||
+
|
||||
+ /* RFC 9114 4.1.2. Malformed Requests and Responses
|
||||
+ *
|
||||
+ * A request or response that is defined as having content when it
|
||||
+ * contains a Content-Length header field (Section 8.6 of [HTTP]) is
|
||||
+ * malformed if the value of the Content-Length header field does not
|
||||
+ * equal the sum of the DATA frame lengths received.
|
||||
+ *
|
||||
+ * TODO for backend support
|
||||
+ * A response that is
|
||||
+ * defined as never having content, even when a Content-Length is
|
||||
+ * present, can have a non-zero Content-Length header field even though
|
||||
+ * no content is included in DATA frames.
|
||||
+ */
|
||||
+ if (h3s->data_len > h3s->body_len ||
|
||||
+ (fin && h3s->data_len < h3s->body_len)) {
|
||||
+ TRACE_ERROR("Content-length does not match DATA frame size", H3_EV_RX_FRAME|H3_EV_RX_DATA, qcs->qcc->conn, qcs);
|
||||
+ ret = -1;
|
||||
+ }
|
||||
+
|
||||
+ TRACE_LEAVE(H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/* Parse from buffer <buf> a H3 HEADERS frame of length <len>. Data are copied
|
||||
* in a local HTX buffer and transfer to the stream connector layer. <fin> must be
|
||||
* set if this is the last data to transfer from this stream.
|
||||
@@ -343,8 +388,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
struct http_hdr list[global.tune.max_http_hdr];
|
||||
unsigned int flags = HTX_SL_F_NONE;
|
||||
struct ist meth = IST_NULL, path = IST_NULL;
|
||||
- //struct ist scheme = IST_NULL, authority = IST_NULL;
|
||||
- struct ist authority = IST_NULL;
|
||||
+ struct ist scheme = IST_NULL, authority = IST_NULL;
|
||||
int hdr_idx, ret;
|
||||
int cookie = -1, last_cookie = -1, i;
|
||||
|
||||
@@ -379,41 +423,113 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
if (ret < 0) {
|
||||
TRACE_ERROR("QPACK decoding error", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
h3c->err = -ret;
|
||||
- return -1;
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
qc_get_buf(qcs, &htx_buf);
|
||||
- BUG_ON(!b_size(&htx_buf));
|
||||
+ BUG_ON(!b_size(&htx_buf)); /* TODO */
|
||||
htx = htx_from_buf(&htx_buf);
|
||||
|
||||
/* first treat pseudo-header to build the start line */
|
||||
hdr_idx = 0;
|
||||
while (1) {
|
||||
- if (isteq(list[hdr_idx].n, ist("")))
|
||||
+ /* RFC 9114 4.3. HTTP Control Data
|
||||
+ *
|
||||
+ * Endpoints MUST treat a request or response that contains
|
||||
+ * undefined or invalid pseudo-header fields as malformed.
|
||||
+ *
|
||||
+ * All pseudo-header fields MUST appear in the header section before
|
||||
+ * regular header fields. Any request or response that contains a
|
||||
+ * pseudo-header field that appears in a header section after a regular
|
||||
+ * header field MUST be treated as malformed.
|
||||
+ */
|
||||
+
|
||||
+ /* Stop at first non pseudo-header. */
|
||||
+ if (!istmatch(list[hdr_idx].n, ist(":")))
|
||||
break;
|
||||
|
||||
- if (istmatch(list[hdr_idx].n, ist(":"))) {
|
||||
- /* pseudo-header */
|
||||
- if (isteq(list[hdr_idx].n, ist(":method")))
|
||||
- meth = list[hdr_idx].v;
|
||||
- else if (isteq(list[hdr_idx].n, ist(":path")))
|
||||
- path = list[hdr_idx].v;
|
||||
- //else if (isteq(list[hdr_idx].n, ist(":scheme")))
|
||||
- // scheme = list[hdr_idx].v;
|
||||
- else if (isteq(list[hdr_idx].n, ist(":authority")))
|
||||
- authority = list[hdr_idx].v;
|
||||
+ /* pseudo-header. Malformed name with uppercase character or
|
||||
+ * invalid token will be rejected in the else clause.
|
||||
+ */
|
||||
+ if (isteq(list[hdr_idx].n, ist(":method"))) {
|
||||
+ if (isttest(meth)) {
|
||||
+ TRACE_ERROR("duplicated method pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ 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);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ meth = list[hdr_idx].v;
|
||||
+ }
|
||||
+ else if (isteq(list[hdr_idx].n, ist(":path"))) {
|
||||
+ if (isttest(path)) {
|
||||
+ TRACE_ERROR("duplicated path pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ path = list[hdr_idx].v;
|
||||
+ }
|
||||
+ else if (isteq(list[hdr_idx].n, ist(":scheme"))) {
|
||||
+ if (isttest(scheme)) {
|
||||
+ /* duplicated pseudo-header */
|
||||
+ TRACE_ERROR("duplicated scheme pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ 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);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ scheme = list[hdr_idx].v;
|
||||
+ }
|
||||
+ else if (isteq(list[hdr_idx].n, ist(":authority"))) {
|
||||
+ if (isttest(authority)) {
|
||||
+ TRACE_ERROR("duplicated authority pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ authority = list[hdr_idx].v;
|
||||
+ }
|
||||
+ else {
|
||||
+ TRACE_ERROR("unknown pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
++hdr_idx;
|
||||
}
|
||||
|
||||
+ if (!istmatch(meth, ist("CONNECT"))) {
|
||||
+ /* RFC 9114 4.3.1. Request Pseudo-Header Fields
|
||||
+ *
|
||||
+ * All HTTP/3 requests MUST include exactly one value for the :method,
|
||||
+ * :scheme, and :path pseudo-header fields, unless the request is a
|
||||
+ * CONNECT request; see Section 4.4.
|
||||
+ */
|
||||
+ if (!isttest(meth) || !isttest(scheme) || !isttest(path)) {
|
||||
+ TRACE_ERROR("missing mandatory pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
flags |= HTX_SL_F_VER_11;
|
||||
flags |= HTX_SL_F_XFER_LEN;
|
||||
|
||||
sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, path, ist("HTTP/3.0"));
|
||||
if (!sl) {
|
||||
h3c->err = H3_INTERNAL_ERROR;
|
||||
- return -1;
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
if (fin)
|
||||
@@ -425,16 +541,22 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
htx_add_header(htx, ist("host"), authority);
|
||||
|
||||
/* now treat standard headers */
|
||||
- hdr_idx = 0;
|
||||
while (1) {
|
||||
if (isteq(list[hdr_idx].n, ist("")))
|
||||
break;
|
||||
|
||||
+ if (istmatch(list[hdr_idx].n, ist(":"))) {
|
||||
+ TRACE_ERROR("pseudo-header field after fields", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < list[hdr_idx].n.len; ++i) {
|
||||
const char c = list[hdr_idx].n.ptr[i];
|
||||
if ((uint8_t)(c - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(c)) {
|
||||
TRACE_ERROR("invalid characters in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
- return -1;
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,29 +564,54 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
http_cookie_register(list, hdr_idx, &cookie, &last_cookie);
|
||||
continue;
|
||||
}
|
||||
+ else if (isteq(list[hdr_idx].n, ist("content-length"))) {
|
||||
+ ret = http_parse_cont_len_header(&list[hdr_idx].v,
|
||||
+ &h3s->body_len,
|
||||
+ h3s->flags & H3_SF_HAVE_CLEN);
|
||||
+ if (ret < 0) {
|
||||
+ TRACE_ERROR("invalid content-length", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ else if (!ret) {
|
||||
+ /* Skip duplicated value. */
|
||||
+ ++hdr_idx;
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
- if (!istmatch(list[hdr_idx].n, ist(":")))
|
||||
- htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v);
|
||||
+ h3s->flags |= H3_SF_HAVE_CLEN;
|
||||
+ /* This will fail if current frame is the last one and
|
||||
+ * content-length is not null.
|
||||
+ */
|
||||
+ if (h3_check_body_size(qcs, fin)) {
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
+ htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v);
|
||||
++hdr_idx;
|
||||
}
|
||||
|
||||
if (cookie >= 0) {
|
||||
if (http_cookie_merge(htx, list, cookie)) {
|
||||
h3c->err = H3_INTERNAL_ERROR;
|
||||
- return -1;
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
}
|
||||
}
|
||||
|
||||
htx_add_endof(htx, HTX_BLK_EOH);
|
||||
- htx_to_buf(htx, &htx_buf);
|
||||
-
|
||||
if (fin)
|
||||
htx->flags |= HTX_FL_EOM;
|
||||
|
||||
+ htx_to_buf(htx, &htx_buf);
|
||||
+ htx = NULL;
|
||||
+
|
||||
if (!qc_attach_sc(qcs, &htx_buf)) {
|
||||
h3c->err = H3_INTERNAL_ERROR;
|
||||
- return -1;
|
||||
+ len = -1;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
/* RFC 9114 5.2. Connection Shutdown
|
||||
@@ -480,11 +627,18 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
|
||||
if (qcs->id >= h3c->id_goaway)
|
||||
h3c->id_goaway = qcs->id + 4;
|
||||
|
||||
+ out:
|
||||
+ /* HTX may be non NULL if error before previous htx_to_buf(). */
|
||||
+ if (htx)
|
||||
+ htx_to_buf(htx, &htx_buf);
|
||||
+
|
||||
/* buffer is transferred to the stream connector and set to NULL
|
||||
* except on stream creation error.
|
||||
*/
|
||||
- b_free(&htx_buf);
|
||||
- offer_buffers(NULL, 1);
|
||||
+ if (b_size(&htx_buf)) {
|
||||
+ b_free(&htx_buf);
|
||||
+ offer_buffers(NULL, 1);
|
||||
+ }
|
||||
|
||||
TRACE_LEAVE(H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
|
||||
return len;
|
||||
@@ -683,8 +837,8 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
uint64_t ftype, flen;
|
||||
char last_stream_frame = 0;
|
||||
|
||||
- /* Work on a copy of <rxbuf> */
|
||||
if (!h3s->demux_frame_len) {
|
||||
+ /* Switch to a new frame. */
|
||||
size_t hlen = h3_decode_frm_header(&ftype, &flen, b);
|
||||
if (!hlen)
|
||||
break;
|
||||
@@ -696,6 +850,15 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
h3s->demux_frame_len = flen;
|
||||
total += hlen;
|
||||
|
||||
+ /* Check that content-length is not exceeded on a new DATA frame. */
|
||||
+ if (ftype == H3_FT_DATA) {
|
||||
+ h3s->data_len += flen;
|
||||
+ if (h3s->flags & H3_SF_HAVE_CLEN && h3_check_body_size(qcs, fin)) {
|
||||
+ qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (!h3_is_frame_valid(h3c, qcs, ftype)) {
|
||||
qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
|
||||
return -1;
|
||||
@@ -725,6 +888,12 @@ static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* Check content-length equality with DATA frames length on the last frame. */
|
||||
+ if (fin && h3s->flags & H3_SF_HAVE_CLEN && h3_check_body_size(qcs, fin)) {
|
||||
+ qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
last_stream_frame = (fin && flen == b_data(b));
|
||||
|
||||
h3_inc_frame_type_cnt(h3c->prx_counters, ftype);
|
||||
@@ -1110,6 +1279,8 @@ static int h3_attach(struct qcs *qcs, void *conn_ctx)
|
||||
|
||||
h3s->demux_frame_len = 0;
|
||||
h3s->demux_frame_type = 0;
|
||||
+ h3s->body_len = 0;
|
||||
+ h3s->data_len = 0;
|
||||
h3s->flags = 0;
|
||||
|
||||
if (quic_stream_is_bidi(qcs->id)) {
|
||||
--
|
||||
2.33.0
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
Name: haproxy
|
||||
Version: 2.6.6
|
||||
Release: 13
|
||||
Release: 14
|
||||
Summary: The Reliable, High Performance TCP/HTTP Load Balancer
|
||||
|
||||
License: GPLv2+
|
||||
@ -40,6 +40,7 @@ Patch19: backport-BUG-MINOR-server-source-interface-ignored-from-defau.
|
||||
Patch20: backport-BUG-MINOR-haproxy-only-tid-0-must-not-sleep-if-got-s.patch
|
||||
Patch21: fix-timehopping-in-freq_ctr_total.patch
|
||||
Patch22: backport-BUG-MEDIUM-stream-Prevent-mux-upgrades-if-client-con.patch
|
||||
Patch23: CVE-2024-53008.patch
|
||||
|
||||
BuildRequires: gcc lua-devel pcre2-devel openssl-devel systemd-devel systemd libatomic
|
||||
%ifarch sw_64
|
||||
@ -144,6 +145,9 @@ exit 0
|
||||
%{_mandir}/man1/*
|
||||
|
||||
%changelog
|
||||
* Tue Dec 10 2024 wangkai <13474090681@163.com> - 2.6.6-14
|
||||
- Fix CVE-2024-53008
|
||||
|
||||
* Thu Nov 21 2024 xinghe <xinghe2@h-partners.com> - 2.6.6-13
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user