From fc70ce08f5818a286fb5899a1bc3aff5965a745e Mon Sep 17 00:00:00 2001 From: Fedor Indutny <fedor@indutny.com> Date: Wed, 18 Nov 2020 20:50:21 -0800 Subject: [PATCH] http: unset `F_CHUNKED` on new `Transfer-Encoding` Duplicate `Transfer-Encoding` header should be a treated as a single, but with original header values concatenated with a comma separator. In the light of this, even if the past `Transfer-Encoding` ended with `chunked`, we should be not let the `F_CHUNKED` to leak into the next header, because mere presence of another header indicates that `chunked` is not the last transfer-encoding token. CVE-ID: CVE-2020-8287 PR-URL: https://github.com/nodejs-private/node-private/pull/235 Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com> --- http_parser.c | 7 +++++++ test.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/http_parser.c b/http_parser.c index 9be003e7322..e9b2b9e83b9 100644 --- a/http_parser.c +++ b/http_parser.c @@ -1344,6 +1344,13 @@ size_t http_parser_execute (http_parser *parser, } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { parser->header_state = h_transfer_encoding; parser->uses_transfer_encoding = 1; + + /* Multiple `Transfer-Encoding` headers should be treated as + * one, but with values separate by a comma. + * + * See: https://tools.ietf.org/html/rfc7230#section-3.2.2 + */ + parser->flags &= ~F_CHUNKED; } break; diff --git a/test.c b/test.c index 3f7c77b3494..2e5a9ebd678 100644 --- a/test.c +++ b/test.c @@ -2154,6 +2154,32 @@ const struct message responses[] = ,.body= "2\r\nOK\r\n0\r\n\r\n" ,.num_chunks_complete= 0 } +#define HTTP_200_DUPLICATE_TE_NOT_LAST_CHUNKED 30 +, {.name= "HTTP 200 response with `chunked` and duplicate Transfer-Encoding" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Transfer-Encoding: identity\r\n" + "\r\n" + "2\r\n" + "OK\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= FALSE + ,.message_complete_on_eof= TRUE + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.content_length= -1 + ,.num_headers= 2 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Transfer-Encoding", "identity" } + } + ,.body= "2\r\nOK\r\n0\r\n\r\n" + ,.num_chunks_complete= 0 + } }; /* strnlen() is a POSIX.2008 addition. Can't rely on it being available so