From 6ffcd5d1c4ff7d787f31298e46a3832857aedc51 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 21 Nov 2024 22:01:12 +0100 Subject: [PATCH] BUG/MAJOR: mux-h1: Properly handle wrapping on obuf when dumping the first-line The formatting of the first-line, for a request or a response, does not properly handle the wrapping of the output buffer. This may lead to a data corruption for the current response or eventually for the previous one. Utility functions used to format the first-line of the request or the response rely on the chunk API. So it is not expected to pass a buffer that wraps. Unfortunatly, because of a change performed during the 2.9 dev cycle, the output buffer was direclty used instead of a non-wrapping buffer created from it with b_make() function. It is not an issue for the request because its start-line is always the first block formatted in the output buffer. But for the response, the output may be not empty and may wrap. In that case, the response start-line is dumped at a random position in the buffer, corrupting data. AFAIK, it is only an issue if the HTTP request pipelining is used. To fix the issue, we now take care to create a non-wapping buffer from the output buffer. This patch should fix issues #2779 and #2996. It must be backported as far as 2.9. (cherry picked from commit b150ae46dd97caa5050d8abefc1d9b619ab5ab9a) Signed-off-by: Christopher Faulet (cherry picked from commit 27dd4f4efe1cd4d250b8de7831e711fc37ceee68) Signed-off-by: Christopher Faulet --- src/h1_htx.c | 4 ++++ src/mux_h1.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/h1_htx.c b/src/h1_htx.c index c5b9dd81d835..768d0f06b176 100644 --- a/src/h1_htx.c +++ b/src/h1_htx.c @@ -944,6 +944,7 @@ int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx, /* Appends the H1 representation of the request line to the chunk . It * returns 1 if data are successfully appended, otherwise it returns 0. + * buffer must not wrap. */ int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk) { @@ -978,6 +979,7 @@ int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk) /* Appends the H1 representation of the status line to the chunk . It * returns 1 if data are successfully appended, otherwise it returns 0. + * buffer must not wrap. */ int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk) { @@ -1011,6 +1013,7 @@ int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk) /* Appends the H1 representation of the header with the value to the * chunk . It returns 1 if data are successfully appended, otherwise it * returns 0. + * buffer must not wrap. */ int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk) { @@ -1035,6 +1038,7 @@ int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk /* Appends the H1 representation of the data to the chunk . If * is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if * data are successfully appended, otherwise it returns 0. + * buffer must not wrap. */ int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked) { diff --git a/src/mux_h1.c b/src/mux_h1.c index 9a0f21a340f5..fbe3bc227895 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -2177,6 +2177,7 @@ static size_t h1_make_reqline(struct h1s *h1s, struct h1m *h1m, struct htx *htx, { struct h1c *h1c = h1s->h1c; struct htx_blk *blk; + struct buffer outbuf; struct htx_sl *sl; enum htx_blk_type type; uint32_t sz; @@ -2201,11 +2202,14 @@ static size_t h1_make_reqline(struct h1s *h1s, struct h1m *h1m, struct htx *htx, if (b_space_wraps(&h1c->obuf)) b_slow_realign(&h1c->obuf, trash.area, b_data(&h1c->obuf)); + outbuf = b_make(b_tail(&h1c->obuf), b_contig_space(&h1c->obuf), 0, 0); sl = htx_get_blk_ptr(htx, blk); - if (!h1_format_htx_reqline(sl, &h1c->obuf)) + if (!h1_format_htx_reqline(sl, &outbuf)) goto full; + b_add(&h1c->obuf, outbuf.data); + h1s->meth = sl->info.req.meth; h1_parse_req_vsn(h1m, sl); @@ -2260,6 +2264,7 @@ static size_t h1_make_stline(struct h1s *h1s, struct h1m *h1m, struct htx *htx, { struct h1c *h1c = h1s->h1c; struct htx_blk *blk; + struct buffer outbuf; struct htx_sl *sl; enum htx_blk_type type; uint32_t sz; @@ -2286,11 +2291,14 @@ static size_t h1_make_stline(struct h1s *h1s, struct h1m *h1m, struct htx *htx, if (b_space_wraps(&h1c->obuf)) b_slow_realign(&h1c->obuf, trash.area, b_data(&h1c->obuf)); + outbuf = b_make(b_tail(&h1c->obuf), b_contig_space(&h1c->obuf), 0, 0); sl = htx_get_blk_ptr(htx, blk); - if (!h1_format_htx_stline(sl, &h1c->obuf)) + if (!h1_format_htx_stline(sl, &outbuf)) goto full; + b_add(&h1c->obuf, outbuf.data); + h1s->status = sl->info.res.status; h1_parse_res_vsn(h1m, sl);