Skip to content

Commit

Permalink
BUG/MAJOR: mux-h1: Properly handle wrapping on obuf when dumping the …
Browse files Browse the repository at this point in the history
…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 haproxy#2779 and #2996. It must be backported as far as
2.9.

(cherry picked from commit b150ae4)
Signed-off-by: Christopher Faulet <[email protected]>
(cherry picked from commit 27dd4f4)
Signed-off-by: Christopher Faulet <[email protected]>
  • Loading branch information
capflam committed Nov 22, 2024
1 parent 49bf039 commit 6ffcd5d
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/h1_htx.c
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,7 @@ int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,

/* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
* returns 1 if data are successfully appended, otherwise it returns 0.
* <chk> buffer must not wrap.
*/
int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
{
Expand Down Expand Up @@ -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 <sl> to the chunk <chk>. It
* returns 1 if data are successfully appended, otherwise it returns 0.
* <chk> buffer must not wrap.
*/
int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
{
Expand Down Expand Up @@ -1011,6 +1013,7 @@ int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
/* Appends the H1 representation of the header <n> with the value <v> to the
* chunk <chk>. It returns 1 if data are successfully appended, otherwise it
* returns 0.
* <chk> buffer must not wrap.
*/
int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
{
Expand All @@ -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 <data> to the chunk <chk>. If
* <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
* data are successfully appended, otherwise it returns 0.
* <chk> buffer must not wrap.
*/
int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
{
Expand Down
12 changes: 10 additions & 2 deletions src/mux_h1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand Down

0 comments on commit 6ffcd5d

Please sign in to comment.