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();