0

[RWS] Add CHECK that no set is a singleton

The RWS parser *should* uphold this invariant, but making this
invariant explicit in the type's ctor allows our fuzzers to tell us if
they are able to break the invariant.

Change-Id: I89c25321bf97096740dbecd5c900bc0f1a61e391
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5122551
Auto-Submit: Chris Fredrickson <cfredric@chromium.org>
Commit-Queue: Sam LeDoux <sledoux@chromium.org>
Reviewed-by: Sam LeDoux <sledoux@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1238146}
This commit is contained in:
Chris Fredrickson
2023-12-15 18:20:44 +00:00
committed by Chromium LUCI CQ
parent af54d2f0ed
commit 3f6dcdc661
4 changed files with 52 additions and 11 deletions

@ -39,7 +39,7 @@ GURL GetTopLevelURL() {
}
GURL GetRequesterURL() {
return GURL("https://requester.example.com");
return GURL("https://requester.com");
}
GURL GetDummyEmbeddingUrl() {
@ -198,14 +198,16 @@ class TopLevelStorageAccessPermissionContextAPIWithFirstPartySetsTest
void SetUp() override {
TopLevelStorageAccessPermissionContextTestAPIEnabledTest::SetUp();
// Create a FPS with https://requester.example.com as the member and
// https://embedder.example.com as the primary.
const net::SchemefulSite top_level(GetTopLevelURL());
first_party_sets_handler_.SetGlobalSets(net::GlobalFirstPartySets(
base::Version("1.2.3"),
/*entries=*/
{{net::SchemefulSite(GetRequesterURL()),
{net::FirstPartySetEntry(net::SchemefulSite(GetTopLevelURL()),
net::SiteType::kAssociated, 0)}}},
{
{net::SchemefulSite(GetRequesterURL()),
net::FirstPartySetEntry(top_level, net::SiteType::kAssociated, 0)},
{top_level, net::FirstPartySetEntry(
top_level, net::SiteType::kPrimary, absl::nullopt)},
},
/*aliases=*/{}));
}

@ -4,6 +4,7 @@
#include "net/first_party_sets/global_first_party_sets.h"
#include <set>
#include <tuple>
#include "base/containers/contains.h"
@ -89,14 +90,15 @@ GlobalFirstPartySets::GlobalFirstPartySets(
aliases_(std::move(aliases)),
manual_config_(std::move(manual_config)),
manual_aliases_(std::move(manual_aliases)) {
if (public_sets_version_.IsValid()) {
CHECK(base::ranges::all_of(aliases_, [&](const auto& pair) {
return entries_.contains(pair.second);
}));
} else {
if (!public_sets_version_.IsValid()) {
CHECK(entries_.empty());
CHECK(aliases_.empty());
}
CHECK(base::ranges::all_of(aliases_, [&](const auto& pair) {
return entries_.contains(pair.second);
}));
CHECK(!ContainsSingleton());
}
GlobalFirstPartySets::GlobalFirstPartySets(GlobalFirstPartySets&&) = default;
@ -205,6 +207,8 @@ void GlobalFirstPartySets::ApplyManuallySpecifiedSet(
/*replacement_sets=*/{manual_entries},
/*addition_sets=*/{}));
manual_aliases_ = std::move(manual_aliases);
CHECK(!ContainsSingleton());
}
void GlobalFirstPartySets::UnsafeSetManualConfig(
@ -476,6 +480,28 @@ void GlobalFirstPartySets::ForEachAlias(
}
}
bool GlobalFirstPartySets::ContainsSingleton() const {
std::set<SchemefulSite> possible_singletons;
std::set<SchemefulSite> not_singletons;
ForEachEffectiveSetEntry(
nullptr,
[&](const SchemefulSite& site, const FirstPartySetEntry& entry) -> bool {
if (!not_singletons.contains(entry.primary())) {
if (site == entry.primary()) {
possible_singletons.insert(entry.primary());
} else {
not_singletons.insert(entry.primary());
possible_singletons.erase(entry.primary());
}
}
return true;
});
return !possible_singletons.empty();
}
std::ostream& operator<<(std::ostream& os, const GlobalFirstPartySets& sets) {
os << "{entries = {";
for (const auto& [site, entry] : sets.entries_) {

@ -172,6 +172,10 @@ class NET_EXPORT GlobalFirstPartySets {
void ForEachAlias(base::FunctionRef<void(const SchemefulSite&,
const SchemefulSite&)> f) const;
// Returns true iff this instance contains a singleton set (a set with only
// one site).
bool ContainsSingleton() const;
// The version associated with the component_updater-provided public sets.
// This may be invalid if the "First-Party Sets" component has not been
// installed yet, or has been corrupted. Entries and aliases from invalid

@ -133,12 +133,15 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_Exists) {
TEST_F(GlobalFirstPartySetsTest, FindEntry_NoNormalization) {
SchemefulSite https_example(GURL("https://example.test"));
SchemefulSite associated(GURL("https://associated.test"));
SchemefulSite wss_example(GURL("wss://example.test"));
FirstPartySetEntry entry(https_example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry assoc_entry(https_example, SiteType::kAssociated, 0);
EXPECT_THAT(GlobalFirstPartySets(kVersion,
{
{https_example, entry},
{associated, assoc_entry},
},
{})
.FindEntry(wss_example, FirstPartySetsContextConfig()),
@ -147,7 +150,9 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_NoNormalization) {
TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverride) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite associated(GURL("https://associated.test"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry assoc_entry(example, SiteType::kAssociated, 0);
FirstPartySetEntry override_entry(example, SiteType::kAssociated, 1);
FirstPartySetsContextConfig config(
@ -156,6 +161,7 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverride) {
EXPECT_THAT(GlobalFirstPartySets(kVersion,
{
{example, public_entry},
{associated, assoc_entry},
},
{})
.FindEntry(example, config),
@ -164,7 +170,9 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_ExistsViaOverride) {
TEST_F(GlobalFirstPartySetsTest, FindEntry_RemovedViaOverride) {
SchemefulSite example(GURL("https://example.test"));
SchemefulSite associated(GURL("https://associated.test"));
FirstPartySetEntry public_entry(example, SiteType::kPrimary, absl::nullopt);
FirstPartySetEntry assoc_entry(example, SiteType::kAssociated, 0);
FirstPartySetsContextConfig config(
{{example, net::FirstPartySetEntryOverride()}});
@ -172,6 +180,7 @@ TEST_F(GlobalFirstPartySetsTest, FindEntry_RemovedViaOverride) {
EXPECT_THAT(GlobalFirstPartySets(kVersion,
{
{example, public_entry},
{associated, assoc_entry},
},
{})
.FindEntry(example, config),