Reset stream if stream frame contains data that goes beyond stream's close offset. This fixes http://crbug/1002119 gfe-relnote: protected by gfe2_reloadable_flag_quic_rst_if_stream_frame_beyond_close_offset. PiperOrigin-RevId: 268732204 Change-Id: I66f845e320de89e8634b1bfb0725f599fc43dfd6
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc index 1be1786..e69cd60 100644 --- a/quic/core/quic_error_codes.cc +++ b/quic/core/quic_error_codes.cc
@@ -29,6 +29,7 @@ RETURN_STRING_LITERAL(QUIC_INVALID_PROMISE_METHOD); RETURN_STRING_LITERAL(QUIC_PUSH_STREAM_TIMED_OUT); RETURN_STRING_LITERAL(QUIC_HEADERS_TOO_LARGE); + RETURN_STRING_LITERAL(QUIC_DATA_AFTER_CLOSE_OFFSET); RETURN_STRING_LITERAL(QUIC_STREAM_TTL_EXPIRED); } // Return a default value so that we return this when |error| doesn't match
diff --git a/quic/core/quic_error_codes.h b/quic/core/quic_error_codes.h index e07094c..298029f 100644 --- a/quic/core/quic_error_codes.h +++ b/quic/core/quic_error_codes.h
@@ -54,6 +54,8 @@ QUIC_HEADERS_TOO_LARGE, // The data is not likely arrive in time. QUIC_STREAM_TTL_EXPIRED, + // The stream received data that goes beyond its close offset. + QUIC_DATA_AFTER_CLOSE_OFFSET, // No error. Used as bound while iterating. QUIC_STREAM_LAST_ERROR, };
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index a75d948..90c7e83 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -2717,6 +2717,25 @@ EXPECT_FALSE(session_.WillingAndAbleToWrite()); } +// Regression test for +// https://bugs.chromium.org/p/chromium/issues/detail?id=1002119 +TEST_P(QuicSessionTestServer, StreamFrameReceivedAfterFin) { + TestStream* stream = session_.CreateOutgoingBidirectionalStream(); + QuicStreamFrame frame(stream->id(), true, 0, ","); + session_.OnStreamFrame(frame); + + QuicStreamFrame frame1(stream->id(), false, 1, ","); + if (GetQuicReloadableFlag(quic_rst_if_stream_frame_beyond_close_offset)) { + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(stream->id(), QUIC_DATA_AFTER_CLOSE_OFFSET)); + session_.OnStreamFrame(frame1); + EXPECT_TRUE(connection_->connected()); + } else { + EXPECT_DEBUG_DEATH(session_.OnStreamFrame(frame1), "Check failed"); + } +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc index 43b8db8..ae302b9 100644 --- a/quic/core/quic_stream.cc +++ b/quic/core/quic_stream.cc
@@ -6,6 +6,7 @@ #include <string> +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_flow_controller.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" @@ -163,6 +164,12 @@ return; } + if (GetQuicReloadableFlag(quic_rst_if_stream_frame_beyond_close_offset) && + frame.offset + frame.data_length > sequencer_.close_offset()) { + Reset(QUIC_DATA_AFTER_CLOSE_OFFSET); + return; + } + if (frame.fin) { fin_received_ = true; } @@ -387,6 +394,15 @@ frame.data_length, ". ", sequencer_.DebugString())); return; } + + if (GetQuicReloadableFlag(quic_rst_if_stream_frame_beyond_close_offset)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_rst_if_stream_frame_beyond_close_offset); + if (frame.offset + frame.data_length > sequencer_.close_offset()) { + Reset(QUIC_DATA_AFTER_CLOSE_OFFSET); + return; + } + } + if (frame.fin) { fin_received_ = true; if (fin_sent_) {
diff --git a/quic/core/quic_stream_sequencer.cc b/quic/core/quic_stream_sequencer.cc index dc7b0cd..8f84fb9 100644 --- a/quic/core/quic_stream_sequencer.cc +++ b/quic/core/quic_stream_sequencer.cc
@@ -38,6 +38,7 @@ QuicStreamSequencer::~QuicStreamSequencer() {} void QuicStreamSequencer::OnStreamFrame(const QuicStreamFrame& frame) { + DCHECK_LE(frame.offset + frame.data_length, close_offset_); ++num_frames_received_; const QuicStreamOffset byte_offset = frame.offset; const size_t data_len = frame.data_length;
diff --git a/quic/core/quic_stream_sequencer_test.cc b/quic/core/quic_stream_sequencer_test.cc index b57fa6e..8ad845b 100644 --- a/quic/core/quic_stream_sequencer_test.cc +++ b/quic/core/quic_stream_sequencer_test.cc
@@ -370,15 +370,11 @@ EXPECT_TRUE(sequencer_->IsClosed()); } -TEST_F(QuicStreamSequencerTest, MutipleOffsets) { +TEST_F(QuicStreamSequencerTest, MultipleOffsets) { OnFinFrame(3, ""); EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get())); EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); - OnFinFrame(5, ""); - EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get())); - - EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); OnFinFrame(1, ""); EXPECT_EQ(3u, QuicStreamSequencerPeer::GetCloseOffset(sequencer_.get())); @@ -761,10 +757,9 @@ // Regression test for https://crbug.com/992486. TEST_F(QuicStreamSequencerTest, CorruptFinFrames) { SetQuicReloadableFlag(quic_no_stream_data_after_reset, true); - EXPECT_CALL(stream_, OnDataAvailable()).Times(1); EXPECT_CALL(stream_, Reset(QUIC_MULTIPLE_TERMINATION_OFFSETS)); - OnFinFrame(0u, ""); + OnFinFrame(2u, ""); OnFinFrame(0u, "a"); EXPECT_FALSE(sequencer_->HasBytesToRead()); }