From d3fd9ac0380099de6bb1fb973234aa278000aecc Mon Sep 17 00:00:00 2001 From: Masakazu Kitajo Date: Wed, 15 Jan 2025 11:10:36 -0700 Subject: [PATCH] Do not allow extra CRs in chunks (#11936) (#11942) * Do not allow extra CRs in chunks (#11936) * Do not allow extra CRs in chunks * Renumber test uuid * Add test cases and fix an oversight * Use prefix increment (cherry picked from commit f5f2256c00abbfd02c22fbae3937da1c7bd8a34f) * Fix test case --- proxy/http/HttpTunnel.cc | 12 +++++ .../bad_chunked_encoding.test.py | 6 +-- .../malformed_chunked_header.replay.yaml | 49 +++++++++++++++++-- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/proxy/http/HttpTunnel.cc b/proxy/http/HttpTunnel.cc index 4b20784f395..adb3cd9bc98 100644 --- a/proxy/http/HttpTunnel.cc +++ b/proxy/http/HttpTunnel.cc @@ -136,6 +136,7 @@ ChunkedHandler::read_size() { int64_t bytes_used; bool done = false; + int cr = 0; while (chunked_reader->read_avail() > 0 && !done) { const char *tmp = chunked_reader->start(); @@ -174,6 +175,9 @@ ChunkedHandler::read_size() done = true; break; } else { + if (ParseRules::is_cr(*tmp)) { + ++cr; + } state = CHUNK_READ_SIZE_CRLF; // now look for CRLF } } @@ -183,7 +187,15 @@ ChunkedHandler::read_size() cur_chunk_bytes_left = (cur_chunk_size = running_sum); state = (running_sum == 0) ? CHUNK_READ_TRAILER_BLANK : CHUNK_READ_CHUNK; done = true; + cr = 0; break; + } else if (ParseRules::is_cr(*tmp)) { + if (cr != 0) { + state = CHUNK_READ_ERROR; + done = true; + break; + } + ++cr; } } else if (state == CHUNK_READ_SIZE_START) { if (ParseRules::is_cr(*tmp)) { diff --git a/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py b/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py index e92181ccdf7..f22cb9d2d39 100644 --- a/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py +++ b/tests/gold_tests/chunked_encoding/bad_chunked_encoding.test.py @@ -172,13 +172,13 @@ def runChunkedTraffic(self): # code from the verifier client. tr.Processes.Default.ReturnCode = 1 tr.Processes.Default.Streams.stdout += Testers.ContainsExpression( - r"(Unexpected chunked content for key 4: too small|Failed HTTP/1 transaction with key: 4)", + r"(Unexpected chunked content for key 101: too small|Failed HTTP/1 transaction with key: 101)", "Verify that ATS closed the forth transaction.") tr.Processes.Default.Streams.stdout += Testers.ContainsExpression( - r"(Unexpected chunked content for key 5: too small|Failed HTTP/1 transaction with key: 5)", + r"(Unexpected chunked content for key 102: too small|Failed HTTP/1 transaction with key: 102)", "Verify that ATS closed the fifth transaction.") tr.Processes.Default.Streams.stdout += Testers.ContainsExpression( - r"(Unexpected chunked content for key 6: too small|Failed HTTP/1 transaction with key: 6)", + r"(Unexpected chunked content for key 103: too small|Failed HTTP/1 transaction with key: 103)", "Verify that ATS closed the sixth transaction.") # ATS should close the connection before any body gets through. "def" diff --git a/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml b/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml index ae135d77ab7..5f136a7eeba 100644 --- a/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml +++ b/tests/gold_tests/chunked_encoding/replays/malformed_chunked_header.replay.yaml @@ -78,6 +78,26 @@ sessions: server-response: status: 200 +- transactions: + - client-request: + method: "POST" + version: "1.1" + url: /malformed/chunk/header3 + headers: + fields: + - [ Host, example.com ] + - [ Transfer-Encoding, chunked ] + - [ uuid, 4 ] + content: + transfer: plain + encoding: uri + # BWS cannot have CR + data: 3%0D%0D%0Aabc%0D%0A0%0D%0A%0D%0A + + # The connection will be dropped and this response will not go out. + server-response: + status: 200 + # # Now repeat the above two malformed chunk header tests, but on the server # side. @@ -90,7 +110,7 @@ sessions: headers: fields: - [ Host, example.com ] - - [ uuid, 4 ] + - [ uuid, 101 ] # The connection will be dropped and this response will not go out. server-response: @@ -113,7 +133,7 @@ sessions: headers: fields: - [ Host, example.com ] - - [ uuid, 5 ] + - [ uuid, 102 ] # The connection will be dropped and this response will not go out. server-response: @@ -136,7 +156,7 @@ sessions: headers: fields: - [ Host, example.com ] - - [ uuid, 6 ] + - [ uuid, 103 ] # The connection will be dropped and this response will not go out. server-response: @@ -150,3 +170,26 @@ sessions: encoding: uri # Super large chunk header, larger than will fit in an int. data: 111111113%0D%0Adef%0D%0A0%0D%0A%0D%0A + +- transactions: + - client-request: + method: "GET" + version: "1.1" + url: /response/malformed/chunk/size2 + headers: + fields: + - [ Host, example.com ] + - [ uuid, 104 ] + + # The connection will be dropped and this response will not go out. + server-response: + status: 200 + reason: OK + headers: + fields: + - [ Transfer-Encoding, chunked ] + content: + transfer: plain + encoding: uri + # BWS cannot have CR + data: 3%0D%0D%0Adef%0D%0A0%0D%0A%0D%0A