From 3a147dab8b90f351b160a89e43e30752c2737387 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 10 Aug 2021 16:30:55 +0200 Subject: [PATCH] BUG/MAJOR: h2: verify that :path starts with a '/' before concatenating it MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Tim Düsterhus found that while the H2 path is checked for non-emptiness, invalid chars and '*', a test is missing to verify that except for '*', it always starts with exactly one '/'. During the reconstruction of the full URI when passing to HTX, this allows to affect the apparent authority by appending a port number or a suffix name. This only affects H2-to-H2 communications, as H2-to-H1 do not use the authority. Like for previous fix, the following rule installed in the frontend or backend is sufficient to renormalize the internal URI: http-request set-header host %[req.hdr(host)] This needs to be backported to 2.2, since earlier versions do not rebuild a full URI using the authority and will fail on the malformed path at the HTTP layer. (cherry picked from commit d3b22b75025246e81ff8d0c78837d4b89d7cf8f8) Signed-off-by: Willy Tarreau (cherry picked from commit 2360306269ff65420cba7c847687a774b1025ab5) Signed-off-by: Willy Tarreau (cherry picked from commit c99c5cd3588a28978cd065abc74508fe81a93a40) Signed-off-by: Willy Tarreau Gbp-Pq: Name 2.2-0003-BUG-MAJOR-h2-verify-that-path-starts-with-a-before-c.patch --- src/h2.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/h2.c b/src/h2.c index bf44611..2648488 100644 --- a/src/h2.c +++ b/src/h2.c @@ -234,6 +234,22 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr, htx->flags |= HTX_FL_PARSING_ERROR; } + if (fields & H2_PHDR_FND_PATH) { + /* 7540#8.1.2.3: :path must not be empty, and must be either + * '*' or an RFC3986 "path-absolute" starting with a "/" but + * not with "//". + */ + if (unlikely(!phdr[H2_PHDR_IDX_PATH].len)) + goto fail; + else if (unlikely(phdr[H2_PHDR_IDX_PATH].ptr[0] != '/')) { + if (!isteq(phdr[H2_PHDR_IDX_PATH], ist("*"))) + goto fail; + } + else if (phdr[H2_PHDR_IDX_PATH].len > 1 && + phdr[H2_PHDR_IDX_PATH].ptr[1] == '/') + goto fail; + } + if (!(flags & HTX_SL_F_HAS_SCHM)) { /* no scheme, use authority only (CONNECT) */ uri = phdr[H2_PHDR_IDX_AUTH]; @@ -244,9 +260,6 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr, * use the trash to concatenate them since all of them MUST fit * in a bufsize since it's where they come from. */ - if (unlikely(!phdr[H2_PHDR_IDX_PATH].len)) - goto fail; // 7540#8.1.2.3: :path must not be empty - uri = ist2bin(trash.area, phdr[H2_PHDR_IDX_SCHM]); istcat(&uri, ist("://"), trash.size); istcat(&uri, phdr[H2_PHDR_IDX_AUTH], trash.size); -- 2.30.2