From 6fc36785addd45cc76a029a023296def53cff135 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 27 Feb 2018 15:37:25 +0100 Subject: [PATCH] BUG/MEDIUM: h2: always consume any trailing data after end of output buffers In case a stream tries to emit more data than advertised by the chunks or content-length headers, the extra data remains in the channel's output buffer until the channel's timeout expires. It can easily happen when sending malformed error files making use of a wrong content-length or having extra CRLFs after the empty chunk. It may also be possible to forge such a bad response using Lua. The H1 to H2 encoder must protect itself against this by marking the data presented to it as consumed if it decides to discard them, so that the sending stream doesn't wait for the timeout to trigger. The visible effect of this problem is a huge memory usage and a high concurrent connection count during benchmarks when using such bad data (a typical place where this easily happens). This fix must be backported to 1.8. (cherry picked from commit 35a62705df65632e2717ae0d20a93e0cb3f8f163) Signed-off-by: Willy Tarreau --- src/mux_h2.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mux_h2.c b/src/mux_h2.c index caae041..4303a06 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -3020,6 +3020,9 @@ static int h2s_frt_make_resp_headers(struct h2s *h2s, struct buffer *buf) * body or directly end in TRL2. */ if (es_now) { + // trim any possibly pending data (eg: inconsistent content-length) + bo_del(buf, buf->o); + h1m->state = HTTP_MSG_DONE; h2s->flags |= H2_SF_ES_SENT; if (h2s->st == H2_SS_OPEN) @@ -3269,8 +3272,12 @@ static int h2s_frt_make_resp_data(struct h2s *h2s, struct buffer *buf) else h2c_stream_close(h2c, h2s); - if (!(h1m->flags & H1_MF_CHNK)) + if (!(h1m->flags & H1_MF_CHNK)) { + // trim any possibly pending data (eg: inconsistent content-length) + bo_del(buf, buf->o); + h1m->state = HTTP_MSG_DONE; + } h2s->flags |= H2_SF_ES_SENT; } @@ -3319,6 +3326,10 @@ static int h2_snd_buf(struct conn_stream *cs, struct buffer *buf, int flags) } total += count; bo_del(buf, count); + + // trim any possibly pending data (eg: extra CR-LF, ...) + bo_del(buf, buf->o); + h2s->res.state = HTTP_MSG_DONE; break; } -- 1.7.10.4