summaryrefslogtreecommitdiffstats
path: root/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch
blob: 11ae6f8eb677a0756c3bc7709ee30155de7f2b84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
From: Willy Tarreau <w@1wt.eu>
Date: Tue, 8 Aug 2023 17:18:27 +0200
Subject: BUG/MAJOR: h3: reject header values containing invalid chars
Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=20a35c4d505475215122d37405ce173075338032

In practice it's exactly the same for h3 as 54f53ef7c ("BUG/MAJOR: h2:
reject header values containing invalid chars") was for h2: we must
make sure never to accept NUL/CR/LF in any header value because this
may be used to construct splitted headers on the backend. Hence we
apply the same solution. Here pseudo-headers, headers and trailers are
checked separately, which explains why we have 3 locations instead of
2 for h2 (+1 for response which we don't have here).

This is marked major for consistency and due to the impact if abused,
but the reality is that at the time of writing, this problem is limited
by the scarcity of the tools which would permit to build such a request
in the first place. But this may change over time.

This must be backported to 2.6. This depends on the following commit
that exposes the filtering function:

    REORG: http: move has_forbidden_char() from h2.c to http.h

(cherry picked from commit d13a80abb7c1badaa42045c37cfff79f24f05726)
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
(cherry picked from commit 0404bf14c900d6ac879ec432a198435e0741d835)
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
(cherry picked from commit f58b63af68f239464c29e698a34f08ff3eef862f)
 [ad: no http/3 trailer support in 2.6]
Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
---
 src/h3.c | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/src/h3.c b/src/h3.c
index 9b4bc6f096d7..b42d41647e4e 100644
--- a/src/h3.c
+++ b/src/h3.c
@@ -401,6 +401,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
 	struct ist scheme = IST_NULL, authority = IST_NULL;
 	int hdr_idx, ret;
 	int cookie = -1, last_cookie = -1, i;
+	const char *ctl;
 
 	/* RFC 9114 4.1.2. Malformed Requests and Responses
 	 *
@@ -464,6 +465,24 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
 		if (!istmatch(list[hdr_idx].n, ist(":")))
 			break;
 
+		/* RFC 9114 10.3 Intermediary-Encapsulation Attacks
+		 *
+		 * While most values that can be encoded will not alter field
+		 * parsing, carriage return (ASCII 0x0d), line feed (ASCII 0x0a),
+		 * and the null character (ASCII 0x00) might be exploited by an
+		 * attacker if they are translated verbatim. Any request or
+		 * response that contains a character not permitted in a field
+		 * value MUST be treated as malformed
+		 */
+
+		/* look for forbidden control characters in the pseudo-header value */
+		ctl = ist_find_ctl(list[hdr_idx].v);
+		if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
+			TRACE_ERROR("control character present in pseudo-header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
+			len = -1;
+			goto out;
+		}
+
 		/* pseudo-header. Malformed name with uppercase character or
 		 * invalid token will be rejected in the else clause.
 		 */
@@ -561,6 +580,25 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
 			}
 		}
 
+
+		/* RFC 9114 10.3 Intermediary-Encapsulation Attacks
+		 *
+		 * While most values that can be encoded will not alter field
+		 * parsing, carriage return (ASCII 0x0d), line feed (ASCII 0x0a),
+		 * and the null character (ASCII 0x00) might be exploited by an
+		 * attacker if they are translated verbatim. Any request or
+		 * response that contains a character not permitted in a field
+		 * value MUST be treated as malformed
+		 */
+
+		/* look for forbidden control characters in the header value */
+		ctl = ist_find_ctl(list[hdr_idx].v);
+		if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
+			TRACE_ERROR("control character present in header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
+			len = -1;
+			goto out;
+		}
+
 		if (isteq(list[hdr_idx].n, ist("cookie"))) {
 			http_cookie_register(list, hdr_idx, &cookie, &last_cookie);
 			++hdr_idx;
-- 
2.43.0