Update to 2.4.22

Resolves: #2196530
This commit is contained in:
Ryan O'Hara 2023-06-06 10:56:45 -05:00
parent c9ad76e1f2
commit 473988d9ab
5 changed files with 6 additions and 277 deletions

View File

@ -1,52 +0,0 @@
From 2c681c6f30fb90adab4701e287ff7a7db669b2e7 Mon Sep 17 00:00:00 2001
From: Christopher Faulet <cfaulet@haproxy.com>
Date: Thu, 22 Dec 2022 09:47:01 +0100
Subject: [PATCH] BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream
flag set
As state in RFC9113#8.1, HEADERS frame with the ES flag set that carries an
informational status code is malformed. However, there is no test on this
condition.
On 2.4 and higher, it is hard to predict consequences of this bug because
end of the message is only reported with a flag. But on 2.2 and lower, it
leads to a crash because there is an unexpected extra EOM block at the end
of an interim response.
Now, when a ES flag is detected on a HEADERS frame for an interim message, a
stream error is sent (RST_STREAM/PROTOCOL_ERROR).
This patch should solve the issue #1972. It should be backported as far as
2.0.
(cherry picked from commit 827a6299e6995c5c3ba620d8b7cbacdaef67f2c4)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit ebfae006c6b5de1d1fe0cdd51847ec1e39d5cf59)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 84f5cba24f59b1c8339bb38323fcb01f434ba8e5)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit f5748a98c34bc889cae9386ca4f7073ab3f4c6b1)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
---
src/mux_h2.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/mux_h2.c b/src/mux_h2.c
index 7d23e5abd..7dbbfefec 100644
--- a/src/mux_h2.c
+++ b/src/mux_h2.c
@@ -4942,6 +4942,11 @@ static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *f
*flags |= H2_SF_HEADERS_RCVD;
if (h2c->dff & H2_F_HEADERS_END_STREAM) {
+ if (msgf & H2_MSGF_RSP_1XX) {
+ /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */
+ TRACE_STATE("invalid interim response with ES flag!", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
+ goto fail;
+ }
/* no more data are expected for this message */
htx->flags |= HTX_FL_EOM;
}
--
2.37.3

View File

@ -1,164 +0,0 @@
From 486cd730485c8a119ef65b3f792134b56e7941b4 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Thu, 9 Feb 2023 21:36:54 +0100
Subject: [PATCH] BUG/CRITICAL: http: properly reject empty http header field
names
The HTTP header parsers surprizingly accepts empty header field names,
and this is a leftover from the original code that was agnostic to this.
When muxes were introduced, for H2 first, the HPACK decompressor needed
to feed headers lists, and since empty header names were strictly
forbidden by the protocol, the lists of headers were purposely designed
to be terminated by an empty header field name (a principle that is
similar to H1's empty line termination). This principle was preserved
and generalized to other protocols migrated to muxes (H1/FCGI/H3 etc)
without anyone ever noticing that the H1 parser was still able to deliver
empty header field names to this list. In addition to this it turns out
that the HPACK decompressor, despite a comment in the code, may
successfully decompress an empty header field name, and this mistake
was propagated to the QPACK decompressor as well.
The impact is that an empty header field name may be used to truncate
the list of headers and thus make some headers disappear. While for
H2/H3 the impact is limited as haproxy sees a request with missing
headers, and headers are not used to delimit messages, in the case of
HTTP/1, the impact is significant because the presence (and sometimes
contents) of certain sensitive headers is detected during the parsing.
Thus, some of these headers may be seen, marked as present, their value
extracted, but never delivered to upper layers and obviously not
forwarded to the other side either. This can have for consequence that
certain important header fields such as Connection, Upgrade, Host,
Content-length, Transfer-Encoding etc are possibly seen as different
between what haproxy uses to parse/forward/route and what is observed
in http-request rules and of course, forwarded. One direct consequence
is that it is possible to exploit this property in HTTP/1 to make
affected versions of haproxy forward more data than is advertised on
the other side, and bypass some access controls or routing rules by
crafting extraneous requests. Note, however, that responses to such
requests will normally not be passed back to the client, but this can
still cause some harm.
This specific risk can be mostly worked around in configuration using
the following rule that will rely on the bug's impact to precisely
detect the inconsistency between the known body size and the one
expected to be advertised to the server (the rule works from 2.0 to
2.8-dev):
http-request deny if { fc_http_major 1 } !{ req.body_size 0 } !{ req.hdr(content-length) -m found } !{ req.hdr(transfer-encoding) -m found } !{ method CONNECT }
This will exclusively block such carefully crafted requests delivered
over HTTP/1. HTTP/2 and HTTP/3 do not need content-length, and a body
that arrives without being announced with a content-length will be
forwarded using transfer-encoding, hence will not cause discrepancies.
In HAProxy 2.0 in legacy mode ("no option http-use-htx"), this rule will
simply have no effect but will not cause trouble either.
A clean solution would consist in modifying the loops iterating over
these headers lists to check the header name's pointer instead of its
length (since both are zero at the end of the list), but this requires
to touch tens of places and it's very easy to miss one. Functions such
as htx_add_header(), htx_add_trailer(), htx_add_all_headers() would be
good starting points for such a possible future change.
Instead the current fix focuses on blocking empty headers where they
are first inserted, hence in the H1/HPACK/QPACK decoders. One benefit
of the current solution (for H1) is that it allows "show errors" to
report a precise diagnostic when facing such invalid HTTP/1 requests,
with the exact location of the problem and the originating address:
$ printf "GET / HTTP/1.1\r\nHost: localhost\r\n:empty header\r\n\r\n" | nc 0 8001
HTTP/1.1 400 Bad request
Content-length: 90
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>
$ socat /var/run/haproxy.stat <<< "show errors"
Total events captured on [10/Feb/2023:16:29:37.530] : 1
[10/Feb/2023:16:29:34.155] frontend decrypt (#2): invalid request
backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:31092
buffer starts at 0 (including 0 out), 16334 free,
len 50, wraps at 16336, error at position 33
H1 connection flags 0x00000000, H1 stream flags 0x00000810
H1 msg state MSG_HDR_NAME(17), H1 msg flags 0x00001410
H1 chunk len 0 bytes, H1 body len 0 bytes :
00000 GET / HTTP/1.1\r\n
00016 Host: localhost\r\n
00033 :empty header\r\n
00048 \r\n
I want to address sincere and warm thanks for their great work to the
team composed of the following security researchers who found the issue
together and reported it: Bahruz Jabiyev, Anthony Gavazzi, and Engin
Kirda from Northeastern University, Kaan Onarlioglu from Akamai
Technologies, Adi Peleg and Harvey Tuch from Google. And kudos to Amaury
Denoyelle from HAProxy Technologies for spotting that the HPACK and
QPACK decoders would let this pass despite the comment explicitly
saying otherwise.
This fix must be backported as far as 2.0. The QPACK changes can be
dropped before 2.6. In 2.0 there is also the equivalent code for legacy
mode, which doesn't suffer from the list truncation, but it would better
be fixed regardless.
CVE-2023-25725 was assigned to this issue.
(cherry picked from commit a8598a2eb11b6c989e81f0dbf10be361782e8d32)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit a0e561ad7f29ed50c473f5a9da664267b60d1112)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit 73be199c4f5f1ed468161a4c5e10ca77cd5989d8)
[wt: dropped QPACK changes for 2.5]
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit f8b2b88aeae15dc3b261cd3749277ae75caf9db8)
Signed-off-by: Willy Tarreau <w@1wt.eu>
---
src/h1.c | 4 ++++
src/hpack-dec.c | 9 +++++++++
2 files changed, 13 insertions(+)
diff --git a/src/h1.c b/src/h1.c
index 4c2e234c5..73de48be0 100644
--- a/src/h1.c
+++ b/src/h1.c
@@ -750,6 +750,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
if (likely(*ptr == ':')) {
col = ptr - start;
+ if (col <= sol) {
+ state = H1_MSG_HDR_NAME;
+ goto http_msg_invalid;
+ }
EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP);
}
diff --git a/src/hpack-dec.c b/src/hpack-dec.c
index 04f3d9ffa..ed39007d1 100644
--- a/src/hpack-dec.c
+++ b/src/hpack-dec.c
@@ -420,6 +420,15 @@ int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len,
/* <name> and <value> are correctly filled here */
}
+ /* We must not accept empty header names (forbidden by the spec and used
+ * as a list termination).
+ */
+ if (!name.len) {
+ hpack_debug_printf("##ERR@%d##\n", __LINE__);
+ ret = -HPACK_ERR_INVALID_ARGUMENT;
+ goto leave;
+ }
+
/* here's what we have here :
* - name.len > 0
* - value is filled with either const data or data allocated from tmp
--
2.37.3

View File

@ -1,51 +0,0 @@
From 0c86fce8028d409de4181e82eec967cfb1e6268e Mon Sep 17 00:00:00 2001
From: Youfu Zhang <zhangyoufu@gmail.com>
Date: Fri, 9 Dec 2022 19:15:48 +0800
Subject: [PATCH] BUG/MAJOR: fcgi: Fix uninitialized reserved bytes
The output buffer is not zero-initialized. If we don't clear reserved
bytes, fcgi requests sent to backend will leak sensitive data.
This patch must be backported as far as 2.2.
(cherry picked from commit 2e6bf0a2722866ae0128a4392fa2375bd1f03ff8)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit db03179fee55c60a92ce6b86a0f04dbb9ba0328b)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit f988992d16f45ef03d5bbb024a1042ed8123e4c5)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 0dc4cdc276d4a0e3347b7c3c4aedca2a2e0ab428)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
---
src/fcgi.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/fcgi.c b/src/fcgi.c
index 1c2543def..778ce9e25 100644
--- a/src/fcgi.c
+++ b/src/fcgi.c
@@ -47,7 +47,7 @@ int fcgi_encode_record_hdr(struct buffer *out, const struct fcgi_header *h)
out->area[len++] = ((h->len >> 8) & 0xff);
out->area[len++] = (h->len & 0xff);
out->area[len++] = h->padding;
- len++; /* rsv */
+ out->area[len++] = 0; /* rsv */
out->data = len;
return 1;
@@ -94,7 +94,11 @@ int fcgi_encode_begin_request(struct buffer *out, const struct fcgi_begin_reques
out->area[len++] = ((r->role >> 8) & 0xff);
out->area[len++] = (r->role & 0xff);
out->area[len++] = r->flags;
- len += 5; /* rsv */
+ out->area[len++] = 0; /* rsv */
+ out->area[len++] = 0;
+ out->area[len++] = 0;
+ out->area[len++] = 0;
+ out->area[len++] = 0;
out->data = len;
return 1;
--
2.39.2

View File

@ -7,8 +7,8 @@
%global _hardened_build 1
Name: haproxy
Version: 2.4.17
Release: 7%{?dist}
Version: 2.4.22
Release: 1%{?dist}
Summary: HAProxy reverse proxy for high availability environments
License: GPLv2+
@ -22,10 +22,6 @@ Source4: %{name}.sysconfig
Source5: %{name}.sysusers
Source6: halog.1
Patch0: bz2161140-refuse-response-end-stream-flag.patch
Patch1: bz2169510-reject-empty-http-header-fields.patch
Patch2: bz2180861-fcgi-fix-uninitialized-reserved-bytes.patch
BuildRequires: gcc
BuildRequires: lua-devel
BuildRequires: pcre2-devel
@ -54,9 +50,6 @@ availability environments. Indeed, it can:
%prep
%setup -q
%patch0 -p1
%patch1 -p1
%patch2 -p1
%build
regparm_opts=
@ -139,6 +132,9 @@ done
%{_sysusersdir}/%{name}.conf
%changelog
* Tue Jun 06 2023 Ryan O'Hara <rohara@redhat.com> - 2.4.22-1
- Update to 2.4.22 (#2196530)
* Tue May 02 2023 Ryan O'Hara <rohara@redhat.com> - 2.4.17-7
- Fix uninitizalized resevered bytes (CVE-2023-0836, #2180861)

View File

@ -1 +1 @@
SHA512 (haproxy-2.4.17.tar.gz) = 98d46b6dbafd95977a32a6479266f3b9fe6e6ed57e39182a3d031add60dabfdaa7494083109a75eaa3e4b15d0293b11081f9b06556eee1777ede40ed6c002a7f
SHA512 (haproxy-2.4.22.tar.gz) = c22ad38046e3c70beb3bf57a62e4e74db329559059e2f36d2f801768c26b1f1222631702e83e9839fab4396c1b78089a807750ff743b4192da06c751cf9f0779