0

fuzzing: rewrite FirstPartySetFuzzer to avoid gRPC dependency

Since we cannot depend on the gRPC corpus anymore, it's a good idea to
start using FuzzTest so that we ensure the generated strings are valid
JSON.

Here, we're using a particular domain that'll both create valid and
invalid JSON. This actually mimics the old corpus, because at every
fuzzer start, we are feeding the string mutator with a valid JSON.
This helps go deeper with a simple string mutator, while still testing
for invalid cases.

Bug: 399449169
Change-Id: I2e81d87323728b933a28fd84de95cb86a63281e6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6308902
Commit-Queue: Paul Semel <paulsemel@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1428401}
This commit is contained in:
Paul Semel
2025-03-05 09:50:32 -08:00
committed by Chromium LUCI CQ
parent cd08b67eed
commit f0ffa8f6c4
6 changed files with 48 additions and 68 deletions

@ -146,6 +146,11 @@ specific_include_rules = {
# content -> tools dependency is disallowed, except buildflags for switches.
"+tools/v8_context_snapshot/buildflags.h",
],
".*_unittest\.(cc|h|m)": [
# unittests can now embed fuzzing tests, and this dependency is needed to
# access FUZZ_TEST macro and various domain generators.
"+third_party/fuzztest",
],
}
new_usages_require_review = True

@ -8,6 +8,9 @@
#include <sstream>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/rand_util.h"
#include "base/test/fuzztest_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/version.h"
#include "content/public/browser/first_party_sets_handler.h"
@ -19,6 +22,7 @@
#include "net/first_party_sets/sets_mutation.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/fuzztest/src/fuzztest/fuzztest.h"
#include "url/gurl.h"
using ::testing::ElementsAre;
@ -1766,4 +1770,42 @@ TEST(FirstPartySetParser,
/*aliases=*/{{associated2_cctld, associated2}}));
}
void ParsesSetsCorrectly(std::string input) {
std::istringstream stream(input);
FirstPartySetParser::ParseSetsFromStream(stream, base::Version("1.0"), false,
false);
}
auto JsonDomain() {
return fuzztest::ReversibleMap(
// The mapping function maps a base::Value to its JSON string
// representation.
[](base::Value value) {
std::string res;
base::JSONWriter::Write(std::move(value), &res);
return res;
},
// The inverse mapping function maps the JSON string representation to
// a tuple of base::Value. The return value is additionally wrapped in
// std::optional.
[](const std::string& value) -> std::optional<std::tuple<base::Value>> {
auto res = base::JSONReader::Read(value);
if (!res) {
return std::nullopt;
}
// We use a tuple because the FuzzTest API requires it, since the
// inverse mapping can map one input value to multiple output values.
return std::tuple{std::move(*res)};
},
fuzztest::Arbitrary<base::Value>());
}
FUZZ_TEST(FirstPartySetFuzzer, ParsesSetsCorrectly)
.WithDomains(fuzztest::OneOf(JsonDomain(),
fuzztest::Arbitrary<std::string>().WithSeeds(
[]() -> std::vector<std::string> {
auto domain = JsonDomain();
return {domain.GetRandomValue(
base::RandomBitGenerator())};
})));
} // namespace content

@ -1,24 +0,0 @@
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/first_party_sets/first_party_set_parser.h"
#include <cstdint>
#include <memory>
#include <sstream>
#include "base/version.h"
namespace content {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::string string_input(reinterpret_cast<const char*>(data), size);
std::istringstream stream(string_input);
FirstPartySetParser::ParseSetsFromStream(stream, base::Version("1.0"), false,
false);
return 0;
}
} // namespace content

@ -1,35 +0,0 @@
# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"{"
"}"
"["
"]"
"\""
"'"
"\\"
"//"
":"
","
" "
"\\n"
"\\r"
"/*"
"*/"
"true"
"false"
"null"
"\\u"
"\\b"
"\\f"
"\\t"
"."
"e"
"e+"
"e-"
"E"
"E+"
"E-"
"owner"
"members"

@ -2962,6 +2962,7 @@ test("content_unittests") {
fuzztests = [
"BiddingAndAuctionSerializerTargetSizeEstimator.DoesNotCrashForAnyInput",
"ActionsParserFuzzTest.ParsesJSONCorrectly",
"FirstPartySetFuzzer.ParsesSetsCorrectly",
]
if (is_mac) {

@ -332,15 +332,6 @@ if (use_fuzzing_engine) {
}
}
fuzzer_test("first_party_set_parser_fuzzer") {
sources =
[ "../../browser/first_party_sets/test/first_party_set_parser_fuzzer.cc" ]
deps = [ ":first_party_set_parser_fuzzer_support" ]
dict =
"../../browser/first_party_sets/test/first_party_set_parser_fuzzer.dict"
seed_corpus = "//third_party/grpc/source/test/core/json/corpus/"
}
fuzzer_test("first_party_set_parser_json_fuzzer") {
sources = [
"../../browser/first_party_sets/test/first_party_set_parser_json_fuzzer.cc",