In QUIC, when creator is consuming data in fast path, close connection if stream data is sent in the wrong encryption level. Protected by gfe2_reloadable_flag_quic_check_encryption_level_in_fast_path. PiperOrigin-RevId: 324666221 Change-Id: I370f76efb1127636e66215fc0fb8dc8b60879988
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc index 109042f..f842538 100644 --- a/quic/core/quic_packet_creator.cc +++ b/quic/core/quic_packet_creator.cc
@@ -1324,6 +1324,13 @@ bool fin, size_t total_bytes_consumed) { DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); + if (GetQuicReloadableFlag(quic_check_encryption_level_in_fast_path)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_check_encryption_level_in_fast_path); + if (AttemptingToSendUnencryptedStreamData()) { + return QuicConsumedData(total_bytes_consumed, + fin && (total_bytes_consumed == write_length)); + } + } while (total_bytes_consumed < write_length && delegate_->ShouldGeneratePacket(HAS_RETRANSMITTABLE_DATA, @@ -1612,14 +1619,7 @@ if (frame.type == STREAM_FRAME && !QuicUtils::IsCryptoStreamId(framer_->transport_version(), frame.stream_frame.stream_id) && - (packet_.encryption_level == ENCRYPTION_INITIAL || - packet_.encryption_level == ENCRYPTION_HANDSHAKE)) { - const std::string error_details = - quiche::QuicheStrCat("Cannot send stream data with level: ", - EncryptionLevelToString(packet_.encryption_level)); - QUIC_BUG << error_details; - delegate_->OnUnrecoverableError( - QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, error_details); + AttemptingToSendUnencryptedStreamData()) { return false; } @@ -1949,6 +1949,20 @@ return largest_payload; } +bool QuicPacketCreator::AttemptingToSendUnencryptedStreamData() { + if (packet_.encryption_level == ENCRYPTION_ZERO_RTT || + packet_.encryption_level == ENCRYPTION_FORWARD_SECURE) { + return false; + } + const std::string error_details = + quiche::QuicheStrCat("Cannot send stream data with level: ", + EncryptionLevelToString(packet_.encryption_level)); + QUIC_BUG << error_details; + delegate_->OnUnrecoverableError(QUIC_ATTEMPT_TO_SEND_UNENCRYPTED_STREAM_DATA, + error_details); + return true; +} + bool QuicPacketCreator::HasIetfLongHeader() const { return VersionHasIetfInvariantHeader(framer_->transport_version()) && packet_.encryption_level < ENCRYPTION_FORWARD_SECURE;
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h index 8db087a..a225793 100644 --- a/quic/core/quic_packet_creator.h +++ b/quic/core/quic_packet_creator.h
@@ -571,6 +571,9 @@ // packet size required for header protection. void MaybeAddExtraPaddingForHeaderProtection(); + // Returns true and close connection if it attempts to send unencrypted data. + bool AttemptingToSendUnencryptedStreamData(); + // Does not own these delegates or the framer. DelegateInterface* delegate_; DebugDelegate* debug_delegate_;
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc index 7943cee..60703fb 100644 --- a/quic/core/quic_packet_creator_test.cc +++ b/quic/core/quic_packet_creator_test.cc
@@ -2593,6 +2593,24 @@ delete rst_frame; } +TEST_F(QuicPacketCreatorMultiplePacketsTest, + WrongEncryptionLevelForStreamDataFastPath) { + if (!GetQuicReloadableFlag(quic_check_encryption_level_in_fast_path)) { + return; + } + creator_.set_encryption_level(ENCRYPTION_HANDSHAKE); + delegate_.SetCanWriteAnything(); + // Create a 10000 byte IOVector. + CreateData(10000); + EXPECT_CALL(delegate_, OnSerializedPacket(_)).Times(0); + EXPECT_CALL(delegate_, OnUnrecoverableError(_, _)); + EXPECT_QUIC_BUG(creator_.ConsumeDataFastPath( + QuicUtils::GetFirstBidirectionalStreamId( + framer_.transport_version(), Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, true), + ""); +} + TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_OnlyAckWritable) { delegate_.SetCanWriteOnlyNonRetransmittable();