Fix check for QuicFramer detecting old header format with new version

Fixes crbug.com/958752, crbug.com/958665, crbug.com/958633

gfe-relnote: Fix bug found by fuzzer; protected by QUIC_VERSION_99 and reloadable flag quic_v44_disable_trial_decryption
PiperOrigin-RevId: 246414836
Change-Id: Iac1a21476e151d382e901133a0209eadd2e17a83
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc
index eb1c8c0..303dca2 100644
--- a/quic/core/quic_framer.cc
+++ b/quic/core/quic_framer.cc
@@ -2404,7 +2404,19 @@
         "Visitor asked to stop processing of unauthenticated header.");
     return false;
   }
-  if (!header->version_flag && version().KnowsWhichDecrypterToUse()) {
+  // The function we are in is called because the framer believes that it is
+  // processing a packet that uses the non-IETF (i.e. Google QUIC) packet header
+  // type. Usually, the framer makes that decision based on the framer's
+  // version, but when the framer is used with Perspective::IS_SERVER, then
+  // before version negotiation is complete (specifically, before
+  // InferPacketHeaderTypeFromVersion is called), this decision is made based on
+  // the type byte of the packet.
+  //
+  // If the framer's version KnowsWhichDecrypterToUse, then that version expects
+  // to use the IETF packet header type. If that's the case and we're in this
+  // function, then the packet received is invalid: the framer was expecting an
+  // IETF packet header and didn't get one.
+  if (version().KnowsWhichDecrypterToUse()) {
     set_detailed_error("Invalid public header type for expected version.");
     return RaiseError(QUIC_INVALID_PACKET_HEADER);
   }
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc
index 3c0b66d..aa5add5 100644
--- a/quic/core/quic_framer_test.cc
+++ b/quic/core/quic_framer_test.cc
@@ -13194,6 +13194,41 @@
   CheckFramingBoundaries(fragments, QUIC_INVALID_PACKET_HEADER);
 }
 
+TEST_P(QuicFramerTest, ProcessMismatchedHeaderVersion) {
+  // The framer needs to have Perspective::IS_SERVER and configured to infer the
+  // packet header type from the packet (not the version). The framer's version
+  // needs to be one that uses the IETF packet format.
+  if (!framer_.version().KnowsWhichDecrypterToUse()) {
+    return;
+  }
+  QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_SERVER);
+
+  // clang-format off
+  PacketFragments packet = {
+    // public flags (long header with version present)
+    {"Unable to read public flags.",
+     {0x09}},
+    // connection_id
+    {"Unable to read ConnectionId.",
+     {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}},
+    // version tag
+    {"Unable to read protocol version.",
+     {QUIC_VERSION_BYTES}},
+    // packet number
+    {"Unable to read packet number.",
+     {0x01}},
+  };
+  // clang-format on
+
+  std::unique_ptr<QuicEncryptedPacket> encrypted(
+      AssemblePacketFromFragments(packet));
+  framer_.ProcessPacket(*encrypted);
+
+  EXPECT_FALSE(framer_.ProcessPacket(*encrypted));
+  EXPECT_EQ(QUIC_INVALID_PACKET_HEADER, framer_.error());
+  CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic