Compare commits
No commits in common. 'c9' and 'i8c' have entirely different histories.
@ -1 +1 @@
|
|||||||
SOURCES/haproxy-2.4.22.tar.gz
|
SOURCES/haproxy-1.8.27.tar.gz
|
||||||
|
@ -1 +1 @@
|
|||||||
d0654cbab48039d998fca2459ce9251c6dbf2ae8 SOURCES/haproxy-2.4.22.tar.gz
|
5a8a12d07da986d2ecba5f57a07a9e68fe597bfd SOURCES/haproxy-1.8.27.tar.gz
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
From 7a18c6a2887b542896a2a0242189e7035155f0d5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Christopher Faulet <cfaulet@haproxy.com>
|
||||||
|
Date: Thu, 22 Oct 2020 14:37:12 +0200
|
||||||
|
Subject: MINOR: ist: Add istend() function to return a pointer to the end of
|
||||||
|
the string
|
||||||
|
|
||||||
|
istend() is a shortcut to istptr() + istlen().
|
||||||
|
|
||||||
|
(cherry picked from commit cf26623780bdd66f4fff4154d0e5081082aff89b)
|
||||||
|
[wt: needed for next fix]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit b12ab9c04a896a90383dbaf5c808a6d9a26cde98)
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit 7a62a17abd2cc6f14a3cca47043db0061e2f6664)
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
---
|
||||||
|
include/common/ist.h | 6 ++++++
|
||||||
|
1 file changed, 6 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/include/common/ist.h b/include/common/ist.h
|
||||||
|
index 5eb8bf23b..fbbfcbef7 100644
|
||||||
|
--- a/include/common/ist.h
|
||||||
|
+++ b/include/common/ist.h
|
||||||
|
@@ -119,6 +119,12 @@ static inline size_t istlen(const struct ist ist)
|
||||||
|
return ist.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* returns the pointer to the end the string */
|
||||||
|
+static inline char *istend(const struct ist ist)
|
||||||
|
+{
|
||||||
|
+ return (ist.ptr + ist.len);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* skips to next character in the string, always stops at the end */
|
||||||
|
static inline struct ist istnext(const struct ist ist)
|
||||||
|
{
|
||||||
|
--
|
||||||
|
2.35.3
|
||||||
|
|
@ -0,0 +1,87 @@
|
|||||||
|
From 379a330ad8a56f6cf1031ff2cd3a093ead7e8585 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Willy Tarreau <w@1wt.eu>
|
||||||
|
Date: Tue, 8 Aug 2023 19:35:25 +0200
|
||||||
|
Subject: DOC: clarify the handling of URL fragments in requests
|
||||||
|
|
||||||
|
We indicate in path/pathq/url that they may contain '#' if the frontend
|
||||||
|
is configured with "option accept-invalid-http-request", and that option
|
||||||
|
mentions the fragment as well.
|
||||||
|
|
||||||
|
(cherry picked from commit 7ab4949ef107a7088777f954de800fe8cf727796)
|
||||||
|
[ad: backported as a companion to BUG/MINOR: h1: do not accept '#' as
|
||||||
|
part of the URI component]
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit 965fb74eb180ab4f275ef907e018128e7eee0e69)
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit e9903d6073ce9ff0ed8b304700e9d2b435ed8050)
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit c47814a58ec153a526e8e9e822cda6e66cef5cc2)
|
||||||
|
[wt: minor ctx adj]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit 3706e1754b925e56951b604cce63f3bb290ed838)
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit b5062da485e78f4448a617a0f8b67dc5b23065d5)
|
||||||
|
[wt: dropped pathq]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit 1ee98d04314d35b694206195b8399c501776afc5)
|
||||||
|
[wt: allow to run with version 1.8]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
---
|
||||||
|
doc/configuration.txt | 15 ++++++++++++---
|
||||||
|
reg-tests/http-rules/fragment_in_uri.vtc | 2 +-
|
||||||
|
2 files changed, 13 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/configuration.txt b/doc/configuration.txt
|
||||||
|
index b30aaa9fb..c0607519a 100644
|
||||||
|
--- a/doc/configuration.txt
|
||||||
|
+++ b/doc/configuration.txt
|
||||||
|
@@ -5433,7 +5433,8 @@ no option accept-invalid-http-request
|
||||||
|
remaining ones are blocked by default unless this option is enabled. This
|
||||||
|
option also relaxes the test on the HTTP version, it allows HTTP/0.9 requests
|
||||||
|
to pass through (no version specified) and multiple digits for both the major
|
||||||
|
- and the minor version.
|
||||||
|
+ and the minor version. Finally, this option also allows incoming URLs to
|
||||||
|
+ contain fragment references ('#' after the path).
|
||||||
|
|
||||||
|
This option should never be enabled by default as it hides application bugs
|
||||||
|
and open security breaches. It should only be deployed after a problem has
|
||||||
|
@@ -15328,7 +15329,11 @@ path : string
|
||||||
|
information from databases and keep them in caches. Note that with outgoing
|
||||||
|
caches, it would be wiser to use "url" instead. With ACLs, it's typically
|
||||||
|
used to match exact file names (e.g. "/login.php"), or directory parts using
|
||||||
|
- the derivative forms. See also the "url" and "base" fetch methods.
|
||||||
|
+ the derivative forms. See also the "url" and "base" fetch methods. Please
|
||||||
|
+ note that any fragment reference in the URI ('#' after the path) is strictly
|
||||||
|
+ forbidden by the HTTP standard and will be rejected. However, if the frontend
|
||||||
|
+ receiving the request has "option accept-invalid-http-request", then this
|
||||||
|
+ fragment part will be accepted and will also appear in the path.
|
||||||
|
|
||||||
|
ACL derivatives :
|
||||||
|
path : exact string match
|
||||||
|
@@ -15502,7 +15507,11 @@ url : string
|
||||||
|
"path" is preferred over using "url", because clients may send a full URL as
|
||||||
|
is normally done with proxies. The only real use is to match "*" which does
|
||||||
|
not match in "path", and for which there is already a predefined ACL. See
|
||||||
|
- also "path" and "base".
|
||||||
|
+ also "path" and "base". Please note that any fragment reference in the URI
|
||||||
|
+ ('#' after the path) is strictly forbidden by the HTTP standard and will be
|
||||||
|
+ rejected. However, if the frontend receiving the request has "option
|
||||||
|
+ accept-invalid-http-request", then this fragment part will be accepted and
|
||||||
|
+ will also appear in the url.
|
||||||
|
|
||||||
|
ACL derivatives :
|
||||||
|
url : exact string match
|
||||||
|
diff --git a/reg-tests/http-rules/fragment_in_uri.vtc b/reg-tests/http-rules/fragment_in_uri.vtc
|
||||||
|
index 621751356..8de0adeb2 100644
|
||||||
|
--- a/reg-tests/http-rules/fragment_in_uri.vtc
|
||||||
|
+++ b/reg-tests/http-rules/fragment_in_uri.vtc
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
varnishtest "check for fragments in URL"
|
||||||
|
-#REQUIRE_VERSION=2.0
|
||||||
|
+#REQUIRE_VERSION=1.8
|
||||||
|
|
||||||
|
# This reg-test checks that '#' is properly blocked in requests
|
||||||
|
|
||||||
|
--
|
||||||
|
2.35.3
|
||||||
|
|
@ -0,0 +1,84 @@
|
|||||||
|
From 5f9b9c909399b51498ddabb39341416381fc06a2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Willy Tarreau <w@1wt.eu>
|
||||||
|
Date: Tue, 8 Aug 2023 15:38:28 +0200
|
||||||
|
Subject: MINOR: h2: pass accept-invalid-http-request down the request parser
|
||||||
|
|
||||||
|
We're adding a new argument "relaxed" to h2_make_htx_request() so that
|
||||||
|
we can control its level of acceptance of certain invalid requests at
|
||||||
|
the proxy level with "option accept-invalid-http-request". The goal
|
||||||
|
will be to add deactivable checks that are still desirable to have by
|
||||||
|
default. For now no test is subject to it.
|
||||||
|
|
||||||
|
(cherry picked from commit d93a00861d714313faa0395ff9e2acb14b0a2fca)
|
||||||
|
[ad: backported for following fix : BUG/MINOR: h2: reject more chars
|
||||||
|
from the :path pseudo header]
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit b6be1a4f858eb6602490c192235114c1a163fef9)
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit 26fa3a285df0748fc79e73e552161268b66fb527)
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit 014945a1508f43e88ac4e89950fa9037e4fb0679)
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit f86e994f5fb5851cd6e4f7f6b366e37765014b9f)
|
||||||
|
[wt: adjusted ctx in h2.h]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit d87aeb80c45cc504274188f0e5048148f3c4f2ff)
|
||||||
|
[wt: extended to h2_make_h1_request() as well for legacy mode]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit f2436eab7d21bab3d85cb750023a1770411f716e)
|
||||||
|
[wt: only kept the legacy mode part (h2-to-h1)]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
---
|
||||||
|
include/common/h2.h | 2 +-
|
||||||
|
src/h2.c | 6 +++++-
|
||||||
|
src/mux_h2.c | 3 ++-
|
||||||
|
3 files changed, 8 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/include/common/h2.h b/include/common/h2.h
|
||||||
|
index 0cecc2d4e..ef15f3cda 100644
|
||||||
|
--- a/include/common/h2.h
|
||||||
|
+++ b/include/common/h2.h
|
||||||
|
@@ -180,7 +180,7 @@ enum h2_err {
|
||||||
|
|
||||||
|
/* various protocol processing functions */
|
||||||
|
|
||||||
|
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf);
|
||||||
|
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf, int relaxed);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some helpful debugging functions.
|
||||||
|
diff --git a/src/h2.c b/src/h2.c
|
||||||
|
index 014e40212..cb40b2e1b 100644
|
||||||
|
--- a/src/h2.c
|
||||||
|
+++ b/src/h2.c
|
||||||
|
@@ -166,8 +166,12 @@ static int h2_prepare_h1_reqline(uint32_t fields, struct ist *phdr, char **ptr,
|
||||||
|
*
|
||||||
|
* The Cookie header will be reassembled at the end, and for this, the <list>
|
||||||
|
* will be used to create a linked list, so its contents may be destroyed.
|
||||||
|
+ *
|
||||||
|
+ * When <relaxed> is non-nul, some non-dangerous checks will be ignored. This
|
||||||
|
+ * is in order to satisfy "option accept-invalid-http-request" for
|
||||||
|
+ * interoperability purposes.
|
||||||
|
*/
|
||||||
|
-int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf)
|
||||||
|
+int h2_make_h1_request(struct http_hdr *list, char *out, int osize, unsigned int *msgf, int relaxed)
|
||||||
|
{
|
||||||
|
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
|
||||||
|
char *out_end = out + osize;
|
||||||
|
diff --git a/src/mux_h2.c b/src/mux_h2.c
|
||||||
|
index 79e70f60b..ecd9c59f8 100644
|
||||||
|
--- a/src/mux_h2.c
|
||||||
|
+++ b/src/mux_h2.c
|
||||||
|
@@ -2844,7 +2844,8 @@ static int h2_frt_decode_headers(struct h2s *h2s, struct buffer *buf, int count)
|
||||||
|
|
||||||
|
/* OK now we have our header list in <list> */
|
||||||
|
msgf = (h2c->dff & H2_F_DATA_END_STREAM) ? 0 : H2_MSGF_BODY;
|
||||||
|
- outlen = h2_make_h1_request(list, bi_end(buf), try, &msgf);
|
||||||
|
+ outlen = h2_make_h1_request(list, bi_end(buf), try, &msgf,
|
||||||
|
+ !!(((const struct session *)h2c->conn->owner)->fe->options2 & PR_O2_REQBUG_OK));
|
||||||
|
|
||||||
|
if (outlen < 0) {
|
||||||
|
h2c_error(h2c, H2_ERR_COMPRESSION_ERROR);
|
||||||
|
--
|
||||||
|
2.35.3
|
||||||
|
|
@ -0,0 +1,77 @@
|
|||||||
|
From 2d848a09fb7a1fb661a418cc07c59496d7eb6b3e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Willy Tarreau <w@1wt.eu>
|
||||||
|
Date: Tue, 8 Aug 2023 19:53:51 +0200
|
||||||
|
Subject: REGTESTS: http-rules: verify that we block '#' by default for
|
||||||
|
normalize-uri
|
||||||
|
|
||||||
|
Since we now block fragments by default, let's add an extra test there
|
||||||
|
to confirm that it's blocked even when stripping it.
|
||||||
|
|
||||||
|
(cherry picked from commit 4d0175b54b2b4eeb01aa6e31282b0a5b0d7d8ace)
|
||||||
|
[ad: backported to test conformance of BUG/MINOR: h1: do not accept '#'
|
||||||
|
as part of the URI component]
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit b3f26043df74c661155566a0abd56103e8116078)
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit 41d161ccbbfa846b4b17ed0166ff08f6bf0c3ea1)
|
||||||
|
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
||||||
|
(cherry picked from commit b6b330eb117d520a890e5b3cd623eaa73479db1b)
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit 73b9b13ac2654ef5384789685e3d65ca5f2f880a)
|
||||||
|
[wt: rewrote the test for 2.2 without normalize-uri and called it
|
||||||
|
fragments-in-uri]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit dbf47600f63ffe161ce08d2f0faef7e0deb32b6e)
|
||||||
|
[wt: removed tune.idle-pool.shared from global section]
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
(cherry picked from commit f04fec9f3efe7f8b70fbe72d6a4473f01699728c)
|
||||||
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
||||||
|
---
|
||||||
|
reg-tests/http-rules/fragment_in_uri.vtc | 35 ++++++++++++++++++++++++
|
||||||
|
1 file changed, 35 insertions(+)
|
||||||
|
create mode 100644 reg-tests/http-rules/fragment_in_uri.vtc
|
||||||
|
|
||||||
|
diff --git a/reg-tests/http-rules/fragment_in_uri.vtc b/reg-tests/http-rules/fragment_in_uri.vtc
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..621751356
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/reg-tests/http-rules/fragment_in_uri.vtc
|
||||||
|
@@ -0,0 +1,35 @@
|
||||||
|
+varnishtest "check for fragments in URL"
|
||||||
|
+#REQUIRE_VERSION=2.0
|
||||||
|
+
|
||||||
|
+# This reg-test checks that '#' is properly blocked in requests
|
||||||
|
+
|
||||||
|
+feature ignore_unknown_macro
|
||||||
|
+
|
||||||
|
+server s1 {
|
||||||
|
+ rxreq
|
||||||
|
+ txresp -hdr "connection: close"
|
||||||
|
+} -start
|
||||||
|
+
|
||||||
|
+haproxy h1 -conf {
|
||||||
|
+ global
|
||||||
|
+
|
||||||
|
+ defaults
|
||||||
|
+ mode http
|
||||||
|
+ timeout connect 1s
|
||||||
|
+ timeout client 1s
|
||||||
|
+ timeout server 1s
|
||||||
|
+
|
||||||
|
+ frontend fe_fragment_block
|
||||||
|
+ bind "fd@${fe_fragment_block}"
|
||||||
|
+ default_backend be
|
||||||
|
+
|
||||||
|
+ backend be
|
||||||
|
+ server s1 ${s1_addr}:${s1_port}
|
||||||
|
+
|
||||||
|
+} -start
|
||||||
|
+
|
||||||
|
+client c11 -connect ${h1_fe_fragment_block_sock} {
|
||||||
|
+ txreq -url "/#foo"
|
||||||
|
+ rxresp
|
||||||
|
+ expect resp.status == 400
|
||||||
|
+} -run
|
||||||
|
--
|
||||||
|
2.35.3
|
||||||
|
|
@ -1,76 +0,0 @@
|
|||||||
From f86e994f5fb5851cd6e4f7f6b366e37765014b9f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Willy Tarreau <w@1wt.eu>
|
|
||||||
Date: Tue, 8 Aug 2023 15:38:28 +0200
|
|
||||||
Subject: [PATCH] MINOR: h2: pass accept-invalid-http-request down the request
|
|
||||||
parser
|
|
||||||
|
|
||||||
We're adding a new argument "relaxed" to h2_make_htx_request() so that
|
|
||||||
we can control its level of acceptance of certain invalid requests at
|
|
||||||
the proxy level with "option accept-invalid-http-request". The goal
|
|
||||||
will be to add deactivable checks that are still desirable to have by
|
|
||||||
default. For now no test is subject to it.
|
|
||||||
|
|
||||||
(cherry picked from commit d93a00861d714313faa0395ff9e2acb14b0a2fca)
|
|
||||||
[ad: backported for following fix : BUG/MINOR: h2: reject more chars
|
|
||||||
from the :path pseudo header]
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit b6be1a4f858eb6602490c192235114c1a163fef9)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit 26fa3a285df0748fc79e73e552161268b66fb527)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit 014945a1508f43e88ac4e89950fa9037e4fb0679)
|
|
||||||
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
||||||
---
|
|
||||||
include/haproxy/h2.h | 2 +-
|
|
||||||
src/h2.c | 6 +++++-
|
|
||||||
src/mux_h2.c | 3 ++-
|
|
||||||
3 files changed, 8 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/include/haproxy/h2.h b/include/haproxy/h2.h
|
|
||||||
index 8d2aa9511..4f872b99d 100644
|
|
||||||
--- a/include/haproxy/h2.h
|
|
||||||
+++ b/include/haproxy/h2.h
|
|
||||||
@@ -207,7 +207,7 @@ extern struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES];
|
|
||||||
/* various protocol processing functions */
|
|
||||||
|
|
||||||
int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned long long *body_len);
|
|
||||||
-int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len);
|
|
||||||
+int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed);
|
|
||||||
int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, char *upgrade_protocol);
|
|
||||||
int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx);
|
|
||||||
|
|
||||||
diff --git a/src/h2.c b/src/h2.c
|
|
||||||
index e1554642e..94c384111 100644
|
|
||||||
--- a/src/h2.c
|
|
||||||
+++ b/src/h2.c
|
|
||||||
@@ -399,8 +399,12 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr,
|
|
||||||
*
|
|
||||||
* The Cookie header will be reassembled at the end, and for this, the <list>
|
|
||||||
* will be used to create a linked list, so its contents may be destroyed.
|
|
||||||
+ *
|
|
||||||
+ * When <relaxed> is non-nul, some non-dangerous checks will be ignored. This
|
|
||||||
+ * is in order to satisfy "option accept-invalid-http-request" for
|
|
||||||
+ * interoperability purposes.
|
|
||||||
*/
|
|
||||||
-int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len)
|
|
||||||
+int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed)
|
|
||||||
{
|
|
||||||
struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
|
|
||||||
uint32_t fields; /* bit mask of H2_PHDR_FND_* */
|
|
||||||
diff --git a/src/mux_h2.c b/src/mux_h2.c
|
|
||||||
index 0ab86534c..61fd1a4d2 100644
|
|
||||||
--- a/src/mux_h2.c
|
|
||||||
+++ b/src/mux_h2.c
|
|
||||||
@@ -4917,7 +4917,8 @@ static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *f
|
|
||||||
if (h2c->flags & H2_CF_IS_BACK)
|
|
||||||
outlen = h2_make_htx_response(list, htx, &msgf, body_len, upgrade_protocol);
|
|
||||||
else
|
|
||||||
- outlen = h2_make_htx_request(list, htx, &msgf, body_len);
|
|
||||||
+ outlen = h2_make_htx_request(list, htx, &msgf, body_len,
|
|
||||||
+ !!(((const struct session *)h2c->conn->owner)->fe->options2 & PR_O2_REQBUG_OK));
|
|
||||||
|
|
||||||
if (outlen < 0 || htx_free_space(htx) < global.tune.maxrewrite) {
|
|
||||||
/* too large headers? this is a stream error only */
|
|
||||||
--
|
|
||||||
2.43.0
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
|||||||
From c7492154ef07d6c08aa1eb52502697bbc3f42a69 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Willy Tarreau <w@1wt.eu>
|
|
||||||
Date: Tue, 8 Aug 2023 19:52:45 +0200
|
|
||||||
Subject: [PATCH] REGTESTS: http-rules: add accept-invalid-http-request for
|
|
||||||
normalize-uri tests
|
|
||||||
|
|
||||||
We'll soon block the '#' by default so let's prepare the test to continue
|
|
||||||
to work.
|
|
||||||
|
|
||||||
(cherry picked from commit 069d0e221e58a46119d7c049bb07fa4bcb8d0075)
|
|
||||||
[ad: backported for following fix : BUG/MINOR: h2: reject more chars
|
|
||||||
from the :path pseudo header]
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit 1660481fab69856a39ac44cf88b76cdbcc0ea954)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit 90d0300cea6cda18a4e20369f4dc0b4c4783d6c9)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit 65849396fd6f192d9f14e81702c6c3851e580345)
|
|
||||||
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
||||||
---
|
|
||||||
reg-tests/http-rules/normalize_uri.vtc | 2 ++
|
|
||||||
1 file changed, 2 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/reg-tests/http-rules/normalize_uri.vtc b/reg-tests/http-rules/normalize_uri.vtc
|
|
||||||
index 6a1dc31dc..56acf2cef 100644
|
|
||||||
--- a/reg-tests/http-rules/normalize_uri.vtc
|
|
||||||
+++ b/reg-tests/http-rules/normalize_uri.vtc
|
|
||||||
@@ -127,6 +127,7 @@ haproxy h1 -conf {
|
|
||||||
|
|
||||||
frontend fe_fragment_strip
|
|
||||||
bind "fd@${fe_fragment_strip}"
|
|
||||||
+ option accept-invalid-http-request
|
|
||||||
|
|
||||||
http-request set-var(txn.before) url
|
|
||||||
http-request normalize-uri fragment-strip
|
|
||||||
@@ -139,6 +140,7 @@ haproxy h1 -conf {
|
|
||||||
|
|
||||||
frontend fe_fragment_encode
|
|
||||||
bind "fd@${fe_fragment_encode}"
|
|
||||||
+ option accept-invalid-http-request
|
|
||||||
|
|
||||||
http-request set-var(txn.before) url
|
|
||||||
http-request normalize-uri fragment-encode
|
|
||||||
--
|
|
||||||
2.43.0
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
|||||||
From ba9afd2774c03e434165475b537d0462801f49bb Mon Sep 17 00:00:00 2001
|
|
||||||
From: Willy Tarreau <w@1wt.eu>
|
|
||||||
Date: Wed, 9 Aug 2023 08:32:48 +0200
|
|
||||||
Subject: [PATCH] BUG/MAJOR: http: reject any empty content-length header value
|
|
||||||
|
|
||||||
The content-length header parser has its dedicated function, in order
|
|
||||||
to take extreme care about invalid, unparsable, or conflicting values.
|
|
||||||
But there's a corner case in it, by which it stops comparing values
|
|
||||||
when reaching the end of the header. This has for a side effect that
|
|
||||||
an empty value or a value that ends with a comma does not deserve
|
|
||||||
further analysis, and it acts as if the header was absent.
|
|
||||||
|
|
||||||
While this is not necessarily a problem for the value ending with a
|
|
||||||
comma as it will be cause a header folding and will disappear, it is a
|
|
||||||
problem for the first isolated empty header because this one will not
|
|
||||||
be recontructed when next ones are seen, and will be passed as-is to the
|
|
||||||
backend server. A vulnerable HTTP/1 server hosted behind haproxy that
|
|
||||||
would just use this first value as "0" and ignore the valid one would
|
|
||||||
then not be protected by haproxy and could be attacked this way, taking
|
|
||||||
the payload for an extra request.
|
|
||||||
|
|
||||||
In field the risk depends on the server. Most commonly used servers
|
|
||||||
already have safe content-length parsers, but users relying on haproxy
|
|
||||||
to protect a known-vulnerable server might be at risk (and the risk of
|
|
||||||
a bug even in a reputable server should never be dismissed).
|
|
||||||
|
|
||||||
A configuration-based work-around consists in adding the following rule
|
|
||||||
in the frontend, to explicitly reject requests featuring an empty
|
|
||||||
content-length header that would have not be folded into an existing
|
|
||||||
one:
|
|
||||||
|
|
||||||
http-request deny if { hdr_len(content-length) 0 }
|
|
||||||
|
|
||||||
The real fix consists in adjusting the parser so that it always expects a
|
|
||||||
value at the beginning of the header or after a comma. It will now reject
|
|
||||||
requests and responses having empty values anywhere in the C-L header.
|
|
||||||
|
|
||||||
This needs to be backported to all supported versions. Note that the
|
|
||||||
modification was made to functions h1_parse_cont_len_header() and
|
|
||||||
http_parse_cont_len_header(). Prior to 2.8 the latter was in
|
|
||||||
h2_parse_cont_len_header(). One day the two should be refused but the
|
|
||||||
former is also used by Lua.
|
|
||||||
|
|
||||||
The HTTP messaging reg-tests were completed to test these cases.
|
|
||||||
|
|
||||||
Thanks to Ben Kallus of Dartmouth College and Narf Industries for
|
|
||||||
reporting this! (this is in GH #2237).
|
|
||||||
|
|
||||||
(cherry picked from commit 6492f1f29d738457ea9f382aca54537f35f9d856)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit a32f99f6f991d123ea3e307bf8aa63220836d365)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit 65921ee12d88e9fb1fa9f6cd8198fd64b3a3f37f)
|
|
||||||
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
|
|
||||||
(cherry picked from commit d17c50010d591d1c070e1cb0567a06032d8869e9)
|
|
||||||
[wt: applied to h2_parse_cont_len_header() in src/h2.c instead]
|
|
||||||
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
||||||
---
|
|
||||||
reg-tests/http-messaging/h1_to_h1.vtc | 26 ++++++++++++
|
|
||||||
reg-tests/http-messaging/h2_to_h1.vtc | 60 +++++++++++++++++++++++++++
|
|
||||||
src/h1.c | 20 +++++++--
|
|
||||||
src/h2.c | 20 +++++++--
|
|
||||||
4 files changed, 120 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/reg-tests/http-messaging/h1_to_h1.vtc b/reg-tests/http-messaging/h1_to_h1.vtc
|
|
||||||
index c7d00858e..603c03210 100644
|
|
||||||
--- a/reg-tests/http-messaging/h1_to_h1.vtc
|
|
||||||
+++ b/reg-tests/http-messaging/h1_to_h1.vtc
|
|
||||||
@@ -275,3 +275,29 @@ client c3h1 -connect ${h1_feh1_sock} {
|
|
||||||
# arrive here.
|
|
||||||
expect_close
|
|
||||||
} -run
|
|
||||||
+
|
|
||||||
+client c4h1 -connect ${h1_feh1_sock} {
|
|
||||||
+ # this request is invalid and advertises an invalid C-L ending with an
|
|
||||||
+ # empty value, which results in a stream error.
|
|
||||||
+ txreq \
|
|
||||||
+ -req "GET" \
|
|
||||||
+ -url "/test31.html" \
|
|
||||||
+ -hdr "content-length: 0," \
|
|
||||||
+ -hdr "connection: close"
|
|
||||||
+ rxresp
|
|
||||||
+ expect resp.status == 400
|
|
||||||
+ expect_close
|
|
||||||
+} -run
|
|
||||||
+
|
|
||||||
+client c5h1 -connect ${h1_feh1_sock} {
|
|
||||||
+ # this request is invalid and advertises an empty C-L, which results
|
|
||||||
+ # in a stream error.
|
|
||||||
+ txreq \
|
|
||||||
+ -req "GET" \
|
|
||||||
+ -url "/test41.html" \
|
|
||||||
+ -hdr "content-length:" \
|
|
||||||
+ -hdr "connection: close"
|
|
||||||
+ rxresp
|
|
||||||
+ expect resp.status == 400
|
|
||||||
+ expect_close
|
|
||||||
+} -run
|
|
||||||
diff --git a/reg-tests/http-messaging/h2_to_h1.vtc b/reg-tests/http-messaging/h2_to_h1.vtc
|
|
||||||
index 0d2b1e5f2..ec7a7c123 100644
|
|
||||||
--- a/reg-tests/http-messaging/h2_to_h1.vtc
|
|
||||||
+++ b/reg-tests/http-messaging/h2_to_h1.vtc
|
|
||||||
@@ -10,6 +10,8 @@ barrier b1 cond 2 -cyclic
|
|
||||||
barrier b2 cond 2 -cyclic
|
|
||||||
barrier b3 cond 2 -cyclic
|
|
||||||
barrier b4 cond 2 -cyclic
|
|
||||||
+barrier b5 cond 2 -cyclic
|
|
||||||
+barrier b6 cond 2 -cyclic
|
|
||||||
|
|
||||||
server s1 {
|
|
||||||
rxreq
|
|
||||||
@@ -31,6 +33,12 @@ server s1 {
|
|
||||||
|
|
||||||
barrier b4 sync
|
|
||||||
# the next request is never received
|
|
||||||
+
|
|
||||||
+ barrier b5 sync
|
|
||||||
+ # the next request is never received
|
|
||||||
+
|
|
||||||
+ barrier b6 sync
|
|
||||||
+ # the next request is never received
|
|
||||||
} -repeat 2 -start
|
|
||||||
|
|
||||||
haproxy h1 -conf {
|
|
||||||
@@ -121,6 +129,32 @@ client c1h2 -connect ${h1_feh2_sock} {
|
|
||||||
txdata -data "this is sent and ignored"
|
|
||||||
rxrst
|
|
||||||
} -run
|
|
||||||
+
|
|
||||||
+ # fifth request is invalid and advertises an invalid C-L ending with an
|
|
||||||
+ # empty value, which results in a stream error.
|
|
||||||
+ stream 9 {
|
|
||||||
+ barrier b5 sync
|
|
||||||
+ txreq \
|
|
||||||
+ -req "GET" \
|
|
||||||
+ -scheme "https" \
|
|
||||||
+ -url "/test5.html" \
|
|
||||||
+ -hdr "content-length" "0," \
|
|
||||||
+ -nostrend
|
|
||||||
+ rxrst
|
|
||||||
+ } -run
|
|
||||||
+
|
|
||||||
+ # sixth request is invalid and advertises an empty C-L, which results
|
|
||||||
+ # in a stream error.
|
|
||||||
+ stream 11 {
|
|
||||||
+ barrier b6 sync
|
|
||||||
+ txreq \
|
|
||||||
+ -req "GET" \
|
|
||||||
+ -scheme "https" \
|
|
||||||
+ -url "/test6.html" \
|
|
||||||
+ -hdr "content-length" "" \
|
|
||||||
+ -nostrend
|
|
||||||
+ rxrst
|
|
||||||
+ } -run
|
|
||||||
} -run
|
|
||||||
|
|
||||||
# HEAD requests : don't work well yet
|
|
||||||
@@ -263,4 +297,30 @@ client c3h2 -connect ${h1_feh2_sock} {
|
|
||||||
txdata -data "this is sent and ignored"
|
|
||||||
rxrst
|
|
||||||
} -run
|
|
||||||
+
|
|
||||||
+ # fifth request is invalid and advertises invalid C-L ending with an
|
|
||||||
+ # empty value, which results in a stream error.
|
|
||||||
+ stream 9 {
|
|
||||||
+ barrier b5 sync
|
|
||||||
+ txreq \
|
|
||||||
+ -req "POST" \
|
|
||||||
+ -scheme "https" \
|
|
||||||
+ -url "/test25.html" \
|
|
||||||
+ -hdr "content-length" "0," \
|
|
||||||
+ -nostrend
|
|
||||||
+ rxrst
|
|
||||||
+ } -run
|
|
||||||
+
|
|
||||||
+ # sixth request is invalid and advertises an empty C-L, which results
|
|
||||||
+ # in a stream error.
|
|
||||||
+ stream 11 {
|
|
||||||
+ barrier b6 sync
|
|
||||||
+ txreq \
|
|
||||||
+ -req "POST" \
|
|
||||||
+ -scheme "https" \
|
|
||||||
+ -url "/test26.html" \
|
|
||||||
+ -hdr "content-length" "" \
|
|
||||||
+ -nostrend
|
|
||||||
+ rxrst
|
|
||||||
+ } -run
|
|
||||||
} -run
|
|
||||||
diff --git a/src/h1.c b/src/h1.c
|
|
||||||
index 73de48be0..eeda311b7 100644
|
|
||||||
--- a/src/h1.c
|
|
||||||
+++ b/src/h1.c
|
|
||||||
@@ -34,13 +34,20 @@ int h1_parse_cont_len_header(struct h1m *h1m, struct ist *value)
|
|
||||||
int not_first = !!(h1m->flags & H1_MF_CLEN);
|
|
||||||
struct ist word;
|
|
||||||
|
|
||||||
- word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
|
|
||||||
+ word.ptr = value->ptr;
|
|
||||||
e = value->ptr + value->len;
|
|
||||||
|
|
||||||
- while (++word.ptr < e) {
|
|
||||||
+ while (1) {
|
|
||||||
+ if (word.ptr >= e) {
|
|
||||||
+ /* empty header or empty value */
|
|
||||||
+ goto fail;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* skip leading delimiter and blanks */
|
|
||||||
- if (unlikely(HTTP_IS_LWS(*word.ptr)))
|
|
||||||
+ if (unlikely(HTTP_IS_LWS(*word.ptr))) {
|
|
||||||
+ word.ptr++;
|
|
||||||
continue;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* digits only now */
|
|
||||||
for (cl = 0, n = word.ptr; n < e; n++) {
|
|
||||||
@@ -79,6 +86,13 @@ int h1_parse_cont_len_header(struct h1m *h1m, struct ist *value)
|
|
||||||
h1m->flags |= H1_MF_CLEN;
|
|
||||||
h1m->curr_len = h1m->body_len = cl;
|
|
||||||
*value = word;
|
|
||||||
+
|
|
||||||
+ /* Now either n==e and we're done, or n points to the comma,
|
|
||||||
+ * and we skip it and continue.
|
|
||||||
+ */
|
|
||||||
+ if (n++ == e)
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
word.ptr = n;
|
|
||||||
}
|
|
||||||
/* here we've reached the end with a single value or a series of
|
|
||||||
diff --git a/src/h2.c b/src/h2.c
|
|
||||||
index dd1f7d9b6..e1554642e 100644
|
|
||||||
--- a/src/h2.c
|
|
||||||
+++ b/src/h2.c
|
|
||||||
@@ -80,13 +80,20 @@ int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned lon
|
|
||||||
int not_first = !!(*msgf & H2_MSGF_BODY_CL);
|
|
||||||
struct ist word;
|
|
||||||
|
|
||||||
- word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
|
|
||||||
+ word.ptr = value->ptr;
|
|
||||||
e = value->ptr + value->len;
|
|
||||||
|
|
||||||
- while (++word.ptr < e) {
|
|
||||||
+ while (1) {
|
|
||||||
+ if (word.ptr >= e) {
|
|
||||||
+ /* empty header or empty value */
|
|
||||||
+ goto fail;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
/* skip leading delimiter and blanks */
|
|
||||||
- if (unlikely(HTTP_IS_LWS(*word.ptr)))
|
|
||||||
+ if (unlikely(HTTP_IS_LWS(*word.ptr))) {
|
|
||||||
+ word.ptr++;
|
|
||||||
continue;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
/* digits only now */
|
|
||||||
for (cl = 0, n = word.ptr; n < e; n++) {
|
|
||||||
@@ -125,6 +132,13 @@ int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned lon
|
|
||||||
*msgf |= H2_MSGF_BODY_CL;
|
|
||||||
*body_len = cl;
|
|
||||||
*value = word;
|
|
||||||
+
|
|
||||||
+ /* Now either n==e and we're done, or n points to the comma,
|
|
||||||
+ * and we skip it and continue.
|
|
||||||
+ */
|
|
||||||
+ if (n++ == e)
|
|
||||||
+ break;
|
|
||||||
+
|
|
||||||
word.ptr = n;
|
|
||||||
}
|
|
||||||
/* here we've reached the end with a single value or a series of
|
|
||||||
--
|
|
||||||
2.43.0
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
u haproxy - "haproxy" /var/lib/haproxy
|
|
@ -0,0 +1,45 @@
|
|||||||
|
From 58b3d8676bbef52bc76dd79ecfcf74582c34ec97 Mon Sep 17 00:00:00 2001
|
||||||
|
From: William Lallemand <wlallemand@haproxy.org>
|
||||||
|
Date: Thu, 17 Dec 2020 18:48:06 +0100
|
||||||
|
Subject: [PATCH] BUG/MEDIUM: mworker: fix again copy_argv()
|
||||||
|
|
||||||
|
When backporting patch df6c5a8 ("BUG/MEDIUM: mworker: fix the copy of
|
||||||
|
options in copy_argv()") part of the patch was removed by mistake.
|
||||||
|
Letting the bug #644 unfixed.
|
||||||
|
|
||||||
|
This patch fixes the problem by reintroducing the missing part.
|
||||||
|
|
||||||
|
1.8 only, no backport needed.
|
||||||
|
---
|
||||||
|
src/haproxy.c | 15 +++++++++++++++
|
||||||
|
1 file changed, 15 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/haproxy.c b/src/haproxy.c
|
||||||
|
index 5ddf4d05..3947505b 100644
|
||||||
|
--- a/src/haproxy.c
|
||||||
|
+++ b/src/haproxy.c
|
||||||
|
@@ -1328,6 +1328,21 @@ static char **copy_argv(int argc, char **argv)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
+ case 'C':
|
||||||
|
+ case 'n':
|
||||||
|
+ case 'm':
|
||||||
|
+ case 'N':
|
||||||
|
+ case 'L':
|
||||||
|
+ case 'f':
|
||||||
|
+ case 'p':
|
||||||
|
+ /* these options have only 1 parameter which must be copied and can start with a '-' */
|
||||||
|
+ *newargv++ = *argv++;
|
||||||
|
+ argc--;
|
||||||
|
+ if (argc == 0)
|
||||||
|
+ goto error;
|
||||||
|
+ *newargv++ = *argv++;
|
||||||
|
+ argc--;
|
||||||
|
+ break;
|
||||||
|
default:
|
||||||
|
/* for other options just copy them without parameters, this is also done
|
||||||
|
* for options like "--foo", but this will fail in the argument parser.
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
From eaf1d768085a924a5322cfc77439ba5a4945bbae Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ryan O'Hara <rohara@redhat.com>
|
||||||
|
Date: Thu, 14 Oct 2021 14:08:39 -0500
|
||||||
|
Subject: [PATCH] Fix short HTTP responses to client
|
||||||
|
|
||||||
|
---
|
||||||
|
src/raw_sock.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/raw_sock.c b/src/raw_sock.c
|
||||||
|
index ad0210105..fbf20ae35 100644
|
||||||
|
--- a/src/raw_sock.c
|
||||||
|
+++ b/src/raw_sock.c
|
||||||
|
@@ -302,7 +302,7 @@ static int raw_sock_to_buf(struct connection *conn, struct buffer *buf, int coun
|
||||||
|
if (ret > 0) {
|
||||||
|
buf->i += ret;
|
||||||
|
done += ret;
|
||||||
|
- if (ret < try) {
|
||||||
|
+ if (0 && ret < try) {
|
||||||
|
/* unfortunately, on level-triggered events, POLL_HUP
|
||||||
|
* is generally delivered AFTER the system buffer is
|
||||||
|
* empty, unless the poller supports POLL_RDHUP. If
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
Loading…
Reference in new issue