PUBLIC: Add a fuzz test for parsing and serializing quic versions This fuzzer immediately found an undefined enum cast in ParseQuicVersionString(). This CL fixes that cast and adds a non-fuzz regression test. PiperOrigin-RevId: 772473029
diff --git a/quiche/quic/core/quic_versions.cc b/quiche/quic/core/quic_versions.cc index 69069ac..f27a5ef 100644 --- a/quiche/quic/core/quic_versions.cc +++ b/quiche/quic/core/quic_versions.cc
@@ -386,7 +386,8 @@ } int quic_version_number = 0; if (absl::SimpleAtoi(version_string, &quic_version_number) && - quic_version_number > 0) { + quic_version_number > 0 && + quic_version_number <= QuicTransportVersion::QUIC_VERSION_MAX_VALUE) { QuicTransportVersion transport_version = static_cast<QuicTransportVersion>(quic_version_number); if (!ParsedQuicVersionIsValid(PROTOCOL_QUIC_CRYPTO, transport_version)) {
diff --git a/quiche/quic/core/quic_versions.h b/quiche/quic/core/quic_versions.h index 682e79a..f8fe6ed 100644 --- a/quiche/quic/core/quic_versions.h +++ b/quiche/quic/core/quic_versions.h
@@ -136,6 +136,7 @@ // version negotiation when proposed by clients and to prevent client // ossification when sent by servers. QUIC_VERSION_RESERVED_FOR_NEGOTIATION = 999, + QUIC_VERSION_MAX_VALUE = QUIC_VERSION_RESERVED_FOR_NEGOTIATION, }; // Helper function which translates from a QuicTransportVersion to a string.
diff --git a/quiche/quic/core/quic_versions_test.cc b/quiche/quic/core/quic_versions_test.cc index 5d2bfaa..2a29895 100644 --- a/quiche/quic/core/quic_versions_test.cc +++ b/quiche/quic/core/quic_versions_test.cc
@@ -6,12 +6,16 @@ #include <cstddef> #include <sstream> +#include <string> #include "absl/algorithm/container.h" #include "absl/base/macros.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" #include "quiche/quic/platform/api/quic_expect_bug.h" #include "quiche/quic/platform/api/quic_flags.h" #include "quiche/quic/platform/api/quic_test.h" +#include "quiche/common/platform/api/quiche_fuzztest.h" namespace quic { namespace test { @@ -353,6 +357,23 @@ EXPECT_EQ("0,Q046", os.str()); } +void ParseSerializeParseIdentityProperty(absl::string_view input) { + ParsedQuicVersionVector parsed = ParseQuicVersionVectorString(input); + std::string serialized = ParsedQuicVersionVectorToString(parsed); + ParsedQuicVersionVector parsed2 = ParseQuicVersionVectorString(serialized); + EXPECT_EQ(parsed, parsed2); +} +FUZZ_TEST(QuicVersionsFuzzTest, ParseSerializeParseIdentityProperty); + +// Regression test for an invalid enum cast to `QuicTransportVersion` in +// `ParseQuicVersionString()`, detected by UndefinedBehaviorSanitizer. +TEST(QuicVersionsTest, ParseSerializeParseIdentityPropertyRegression) { + static constexpr int kInvalidVersion = 99999; + static_assert(kInvalidVersion > QuicTransportVersion::QUIC_VERSION_MAX_VALUE); + EXPECT_EQ(UnsupportedQuicVersion(), + ParseQuicVersionString(absl::StrCat(kInvalidVersion))); +} + TEST(QuicVersionsTest, FilterSupportedVersionsAllVersions) { for (const ParsedQuicVersion& version : AllSupportedVersions()) { QuicEnableVersion(version);