Blame SOURCES/CVE-2018-7159.patch

4c49fc
From c39167dc260953184a1ccd45292947808b94507d Mon Sep 17 00:00:00 2001
4c49fc
From: Ben Noordhuis <info@bnoordhuis.nl>
4c49fc
Date: Tue, 27 Mar 2018 16:45:33 +0200
4c49fc
Subject: [PATCH] deps: reject interior blanks in Content-Length
4c49fc
MIME-Version: 1.0
4c49fc
Content-Type: text/plain; charset=UTF-8
4c49fc
Content-Transfer-Encoding: 8bit
4c49fc
4c49fc
Original commit message follows:
4c49fc
4c49fc
    Before this commit `Content-Length: 4 2` was accepted as a valid
4c49fc
    header and recorded as `parser->content_length = 42`.  Now it is
4c49fc
    a parse error that fails with error `HPE_INVALID_CONTENT_LENGTH`.
4c49fc
4c49fc
    Downstream users that inspect `parser->content_length` and naively
4c49fc
    parse the string value using `strtoul()` might get confused by the
4c49fc
    discrepancy between the two values.  Resolve that by simply not
4c49fc
    letting it happen.
4c49fc
4c49fc
Fixes: https://github.com/nodejs-private/security/issues/178
4c49fc
PR-URL: https://github.com/nodejs-private/http-parser-private/pull/1
4c49fc
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
4c49fc
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
4c49fc
Reviewed-By: Evan Lucas <evanlucas@me.com>
4c49fc
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
4c49fc
Reviewed-By: James M Snell <jasnell@gmail.com>
4c49fc
Reviewed-By: Rod Vagg <rod@vagg.org>
4c49fc
---
4c49fc
 deps/http_parser/http_parser.c | 19 ++++++++++++++++++-
4c49fc
 deps/http_parser/test.c        | 21 +++++++++++++++++++++
4c49fc
 2 files changed, 39 insertions(+), 1 deletion(-)
4c49fc
4c49fc
diff --git a/deps/http_parser/http_parser.c b/deps/http_parser/http_parser.c
4c49fc
index 7a9c688b1ca7..6522618671d0 100644
4c49fc
--- a/deps/http_parser/http_parser.c
4c49fc
+++ b/deps/http_parser/http_parser.c
4c49fc
@@ -370,6 +370,8 @@ enum header_states
4c49fc
 
4c49fc
   , h_connection
4c49fc
   , h_content_length
4c49fc
+  , h_content_length_num
4c49fc
+  , h_content_length_ws
4c49fc
   , h_transfer_encoding
4c49fc
   , h_upgrade
4c49fc
 
4c49fc
@@ -1406,6 +1408,7 @@ size_t http_parser_execute (http_parser *parser,
4c49fc
 
4c49fc
             parser->flags |= F_CONTENTLENGTH;
4c49fc
             parser->content_length = ch - '0';
4c49fc
+            parser->header_state = h_content_length_num;
4c49fc
             break;
4c49fc
 
4c49fc
           case h_connection:
4c49fc
@@ -1493,10 +1496,18 @@ size_t http_parser_execute (http_parser *parser,
4c49fc
               break;
4c49fc
 
4c49fc
             case h_content_length:
4c49fc
+              if (ch == ' ') break;
4c49fc
+              h_state = h_content_length_num;
4c49fc
+              /* FALLTHROUGH */
4c49fc
+
4c49fc
+            case h_content_length_num:
4c49fc
             {
4c49fc
               uint64_t t;
4c49fc
 
4c49fc
-              if (ch == ' ') break;
4c49fc
+              if (ch == ' ') {
4c49fc
+                h_state = h_content_length_ws;
4c49fc
+                break;
4c49fc
+              }
4c49fc
 
4c49fc
               if (UNLIKELY(!IS_NUM(ch))) {
4c49fc
                 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
4c49fc
@@ -1519,6 +1530,12 @@ size_t http_parser_execute (http_parser *parser,
4c49fc
               break;
4c49fc
             }
4c49fc
 
4c49fc
+            case h_content_length_ws:
4c49fc
+              if (ch == ' ') break;
4c49fc
+              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
4c49fc
+              parser->header_state = h_state;
4c49fc
+              goto error;
4c49fc
+
4c49fc
             /* Transfer-Encoding: chunked */
4c49fc
             case h_matching_transfer_encoding_chunked:
4c49fc
               parser->index++;
4c49fc
diff --git a/deps/http_parser/test.c b/deps/http_parser/test.c
4c49fc
index bc4e664f5253..cb445cea8607 100644
4c49fc
--- a/deps/http_parser/test.c
4c49fc
+++ b/deps/http_parser/test.c
4c49fc
@@ -4168,6 +4168,27 @@ main (void)
4c49fc
   test_invalid_header_field_token_error(HTTP_RESPONSE);
4c49fc
   test_invalid_header_field_content_error(HTTP_RESPONSE);
4c49fc
 
4c49fc
+  test_simple_type(
4c49fc
+      "POST / HTTP/1.1\r\n"
4c49fc
+      "Content-Length:  42 \r\n"  // Note the surrounding whitespace.
4c49fc
+      "\r\n",
4c49fc
+      HPE_OK,
4c49fc
+      HTTP_REQUEST);
4c49fc
+
4c49fc
+  test_simple_type(
4c49fc
+      "POST / HTTP/1.1\r\n"
4c49fc
+      "Content-Length: 4 2\r\n"
4c49fc
+      "\r\n",
4c49fc
+      HPE_INVALID_CONTENT_LENGTH,
4c49fc
+      HTTP_REQUEST);
4c49fc
+
4c49fc
+  test_simple_type(
4c49fc
+      "POST / HTTP/1.1\r\n"
4c49fc
+      "Content-Length: 13 37\r\n"
4c49fc
+      "\r\n",
4c49fc
+      HPE_INVALID_CONTENT_LENGTH,
4c49fc
+      HTTP_REQUEST);
4c49fc
+
4c49fc
   //// RESPONSES
4c49fc
 
4c49fc
   test_simple_type("HTP/1.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);