Call Visitor::OnError() from HttpDecoder::RaiseError(). This is to make sure connection is closed on error. This bug was caught by ClusterFuzz at https://crbug.com/989416. gfe-relnote: n/a, change to QUIC v99-only code. Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99. PiperOrigin-RevId: 262337299 Change-Id: Ib5241b0c53228dfe48356f5c03d9f4ffae499611
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc index 550aa6f..e105fc6 100644 --- a/quic/core/http/http_decoder.cc +++ b/quic/core/http/http_decoder.cc
@@ -126,7 +126,6 @@ if (current_frame_length_ > MaxFrameLength(current_frame_type_)) { // TODO(bnc): Signal HTTP_EXCESSIVE_LOAD or similar to peer. RaiseError(QUIC_INTERNAL_ERROR, "Frame is too large"); - visitor_->OnError(this); return false; } @@ -440,6 +439,7 @@ state_ = STATE_ERROR; error_ = error; error_detail_ = std::move(error_detail); + visitor_->OnError(this); } bool HttpDecoder::ParsePriorityFrame(QuicDataReader* reader,
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc index 476c2c6..7cbe949 100644 --- a/quic/core/http/http_decoder_test.cc +++ b/quic/core/http/http_decoder_test.cc
@@ -404,6 +404,7 @@ HttpDecoder decoder(&visitor_); EXPECT_CALL(visitor_, OnPriorityFrameStart(header_length)); + EXPECT_CALL(visitor_, OnError(&decoder)); QuicByteCount processed_bytes = decoder.ProcessInput(input.data(), input.size()); @@ -460,6 +461,40 @@ EXPECT_EQ("", decoder_.error_detail()); } +TEST_F(HttpDecoderTest, CorruptSettingsFrame) { + const char* const kPayload = + "\x42\x11" // two-byte id + "\x80\x22\x33\x44" // four-byte value + "\x58\x39" // two-byte id + "\xf0\x22\x33\x44\x55\x66\x77\x88"; // eight-byte value + struct { + size_t payload_length; + const char* const error_message; + } kTestData[] = { + {1, "Unable to read settings frame identifier"}, + {5, "Unable to read settings frame content"}, + {7, "Unable to read settings frame identifier"}, + {12, "Unable to read settings frame content"}, + }; + + for (const auto& test_data : kTestData) { + std::string input; + input.push_back(4u); // type SETTINGS + input.push_back(test_data.payload_length); + const size_t header_length = input.size(); + input.append(kPayload, test_data.payload_length); + + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnSettingsFrameStart(header_length)); + EXPECT_CALL(visitor_, OnError(&decoder)); + + QuicByteCount processed_bytes = + decoder.ProcessInput(input.data(), input.size()); + EXPECT_EQ(input.size(), processed_bytes); + EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder.error()); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); + } +} TEST_F(HttpDecoderTest, DataFrame) { InSequence s; std::string input( @@ -792,6 +827,57 @@ EXPECT_EQ("", decoder_.error_detail()); } +TEST_F(HttpDecoderTest, CorruptFrame) { + InSequence s; + + struct { + const char* const input; + const char* const error_message; + } kTestData[] = {{"\x03" // type (CANCEL_PUSH) + "\x01" // length + "\x40", // first byte of two-byte varint push id + "Unable to read push_id"}, + {"\x05" // type (PUSH_PROMISE) + "\x01" // length + "\x40", // first byte of two-byte varint push id + "Unable to read push_id"}, + {"\x0D" // type (MAX_PUSH_ID) + "\x01" // length + "\x40", // first byte of two-byte varint push id + "Unable to read push_id"}, + {"\x0E" // type (DUPLICATE_PUSH) + "\x01" // length + "\x40", // first byte of two-byte varint push id + "Unable to read push_id"}, + {"\x07" // type (GOAWAY) + "\x01" // length + "\x40", // first byte of two-byte varint stream id + "Unable to read GOAWAY stream_id"}}; + + for (const auto& test_data : kTestData) { + { + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnError(&decoder)); + + QuicStringPiece input(test_data.input); + decoder.ProcessInput(input.data(), input.size()); + EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder.error()); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); + } + { + HttpDecoder decoder(&visitor_); + EXPECT_CALL(visitor_, OnError(&decoder)); + + QuicStringPiece input(test_data.input); + for (auto c : input) { + decoder.ProcessInput(&c, 1); + } + EXPECT_EQ(QUIC_INTERNAL_ERROR, decoder.error()); + EXPECT_EQ(test_data.error_message, decoder.error_detail()); + } + } +} // namespace test + } // namespace test } // namespace quic