Enforce the limits on the maximum number of ACK timestamps received. PiperOrigin-RevId: 933539307
diff --git a/quiche/quic/core/quic_framer.cc b/quiche/quic/core/quic_framer.cc index df8e07f..cf184f6 100644 --- a/quiche/quic/core/quic_framer.cc +++ b/quiche/quic/core/quic_framer.cc
@@ -3896,6 +3896,8 @@ return true; } + uint64_t total_timestamp_count = 0; + // Iterate through all timestamp ranges, each of which represents a block of // contiguous packets for which receive timestamps are being reported. Each // range is of the form: @@ -3926,6 +3928,11 @@ set_detailed_error("Receive timestamp count too high."); return false; } + total_timestamp_count += timestamp_count; + if (total_timestamp_count > max_receive_timestamps_per_ack_) { + set_detailed_error("Too many receive timestamps in ACK frame."); + return false; + } for (uint64_t j = 0; j < timestamp_count; j++) { uint64_t timestamp_delta; if (!reader->ReadVarInt62(×tamp_delta)) {
diff --git a/quiche/quic/core/quic_framer_test.cc b/quiche/quic/core/quic_framer_test.cc index 306995f..f342eff 100644 --- a/quiche/quic/core/quic_framer_test.cc +++ b/quiche/quic/core/quic_framer_test.cc
@@ -7238,6 +7238,48 @@ "Packet number and/or receive time not in order."); } +TEST_P(QuicFramerTest, ProcessIetfAckReceiveTimestampsExceedsMaxTimestamps) { + if (!VersionIsIetfQuic(framer_.transport_version())) { + return; + } + framer_.InstallDecrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<StrictTaggingDecrypter>(/*key=*/0)); + framer_.SetKeyUpdateSupportForConnection(true); + framer_.set_process_timestamps(true); + framer_.set_max_receive_timestamps_per_ack(8); + framer_.set_receive_timestamps_exponent(3); + + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicAckFrame ack_frame = InitAckFrame(kSmallLargestObserved); + ack_frame.received_packet_times = PacketTimeVector{ + {kSmallLargestObserved - 5, CreationTimePlus((0x29ff << 3))}, + {kSmallLargestObserved - 4, CreationTimePlus((0x29ff << 3))}, + {kSmallLargestObserved - 3, CreationTimePlus((0x29ff << 3))}, + {kSmallLargestObserved - 2, CreationTimePlus((0x29ff << 3))}, + }; + ack_frame.ack_delay_time = QuicTime::Delta::Zero(); + QuicFrames frames = {QuicFrame(&ack_frame)}; + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + std::unique_ptr<QuicEncryptedPacket> encrypted( + EncryptPacketWithTagAndPhase(*data, 0, false)); + ASSERT_TRUE(encrypted); + + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER); + framer_.set_max_receive_timestamps_per_ack(2); + EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); + EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_ACK_DATA)); + EXPECT_EQ("Too many receive timestamps in ACK frame.", + framer_.detailed_error()); +} + // If there's insufficient room for IETF ack receive timestamps, don't write any // timestamp ranges. TEST_P(QuicFramerTest, IetfAckReceiveTimestampsTruncate) {