Disallow invalid MAX_PUSH_ID frame This frame only contains a variable length integer, so its payload length is not allowed to exceed 8 bytes. Note that gfe2_reloadable_flag_quic_reject_large_max_push_id is default-enabled. Protected by FLAGS_quic_reloadable_flag_quic_reject_large_max_push_id. PiperOrigin-RevId: 385247216
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc index 92a2e38..b20789b 100644 --- a/quic/core/http/http_decoder.cc +++ b/quic/core/http/http_decoder.cc
@@ -669,6 +669,13 @@ return 1024 * 1024; case static_cast<uint64_t>(HttpFrameType::GOAWAY): return VARIABLE_LENGTH_INTEGER_LENGTH_8; + case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): + if (GetQuicReloadableFlag(quic_reject_large_max_push_id)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_reject_large_max_push_id); + return VARIABLE_LENGTH_INTEGER_LENGTH_8; + } else { + return std::numeric_limits<QuicByteCount>::max(); + } case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): // This limit is arbitrary. return 1024 * 1024;
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc index 36bc2d1..7fa09ba 100644 --- a/quic/core/http/http_decoder_test.cc +++ b/quic/core/http/http_decoder_test.cc
@@ -603,7 +603,7 @@ EXPECT_EQ("", decoder_.error_detail()); } -TEST_F(HttpDecoderTest, MalformedFrameWithOverlyLargePayload) { +TEST_F(HttpDecoderTest, GoawayWithOverlyLargePayload) { std::string input = absl::HexStringToBytes( "07" // type (GOAWAY) "10"); // length exceeding the maximum possible length for GOAWAY frame @@ -614,6 +614,24 @@ EXPECT_EQ("Frame is too large.", decoder_.error_detail()); } +TEST_F(HttpDecoderTest, MaxPushIdWithOverlyLargePayload) { + std::string input = absl::HexStringToBytes( + "0d" // type (MAX_PUSH_ID) + "10"); // length exceeding the maximum possible length for MAX_PUSH_ID + // frame + // Process all data at once. + if (GetQuicReloadableFlag(quic_reject_large_max_push_id)) { + EXPECT_CALL(visitor_, OnError(&decoder_)); + EXPECT_EQ(2u, ProcessInput(input)); + EXPECT_THAT(decoder_.error(), IsError(QUIC_HTTP_FRAME_TOO_LARGE)); + EXPECT_EQ("Frame is too large.", decoder_.error_detail()); + } else { + EXPECT_EQ(2u, ProcessInput(input)); + EXPECT_THAT(decoder_.error(), IsQuicNoError()); + EXPECT_EQ("", decoder_.error_detail()); + } +} + TEST_F(HttpDecoderTest, MalformedSettingsFrame) { char input[30]; QuicDataWriter writer(30, input);
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h index 08922c7..002dd3b 100644 --- a/quic/core/quic_flags_list.h +++ b/quic/core/quic_flags_list.h
@@ -35,6 +35,8 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false) // If true, allow ticket open to be ignored in TlsServerHandshaker. Also fixes TlsServerHandshaker::ResumptionAttempted when handshake hints is used. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_allow_ignore_ticket_open, true) +// If true, close connection if a MAX_PUSH_ID header with length field exceeding maximum valid payload length of 8 bytes is received. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_reject_large_max_push_id, true) // If true, close read side but not write side in QuicSpdyStream::OnStreamReset(). QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_fix_on_stream_reset, true) // If true, default on PTO which unifies TLP + RTO loss recovery.