-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
variations: Add SeedStore override for CrOS.
CrOS early boot needs to have its own notion of what the "safe seed" is (and when to use it), so override the VariationsSeedStore class's LoadSafeSeed method to load a distinct seed from the one in local state. BUG=b:263975722 TEST=included unit tests Change-Id: I87c5135bb6438056f5018c722c888c430da8c35d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4685411 Commit-Queue: Miriam Zimmerman <mutexlox@chromium.org> Reviewed-by: Ian Barkley-Yeung <iby@chromium.org> Reviewed-by: Ilya Sherman <isherman@chromium.org> Cr-Commit-Position: refs/heads/main@{#1187997}
- Loading branch information
Showing
8 changed files
with
312 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
components/variations/cros_evaluate_seed/early_boot_seed_store.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "components/variations/cros_evaluate_seed/early_boot_seed_store.h" | ||
|
||
#include "base/logging.h" | ||
#include "base/time/time.h" | ||
#include "components/variations/client_filterable_state.h" | ||
#include "third_party/abseil-cpp/absl/types/optional.h" | ||
|
||
namespace variations::cros_early_boot::evaluate_seed { | ||
|
||
EarlyBootSeedStore::EarlyBootSeedStore( | ||
PrefService* local_state, | ||
const absl::optional<featured::SeedDetails>& safe_seed_details) | ||
: VariationsSeedStore(local_state), safe_seed_details_(safe_seed_details) {} | ||
|
||
EarlyBootSeedStore::~EarlyBootSeedStore() = default; | ||
|
||
bool EarlyBootSeedStore::LoadSafeSeed(VariationsSeed* seed, | ||
ClientFilterableState* client_state) { | ||
// We require that evaluate_seed's command line specified a safe seed in order | ||
// to use the safe seed. | ||
CHECK(safe_seed_details_.has_value()); | ||
absl::optional<VerifySignatureResult> verify_signature_result; | ||
if (VerifyAndParseSeed(seed, safe_seed_details_->compressed_data(), | ||
safe_seed_details_->signature(), | ||
&verify_signature_result) != | ||
LoadSeedResult::kSuccess) { | ||
return false; | ||
} | ||
|
||
client_state->reference_date = | ||
base::Time::FromJavaTime(safe_seed_details_->date()); | ||
client_state->locale = safe_seed_details_->locale(); | ||
client_state->permanent_consistency_country = | ||
safe_seed_details_->permanent_consistency_country(); | ||
client_state->session_consistency_country = | ||
safe_seed_details_->session_consistency_country(); | ||
|
||
return true; | ||
} | ||
|
||
} // namespace variations::cros_early_boot::evaluate_seed |
51 changes: 51 additions & 0 deletions
51
components/variations/cros_evaluate_seed/early_boot_seed_store.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef COMPONENTS_VARIATIONS_CROS_EVALUATE_SEED_EARLY_BOOT_SEED_STORE_H_ | ||
#define COMPONENTS_VARIATIONS_CROS_EVALUATE_SEED_EARLY_BOOT_SEED_STORE_H_ | ||
|
||
#include "base/time/time.h" | ||
#include "chromeos/ash/components/dbus/featured/featured.pb.h" | ||
#include "components/variations/client_filterable_state.h" | ||
#include "components/variations/proto/variations_seed.pb.h" | ||
#include "components/variations/variations_seed_store.h" | ||
|
||
class PrefService; | ||
|
||
namespace variations::cros_early_boot::evaluate_seed { | ||
|
||
// VariationsSeedStore that uses a safe seed specific to early-boot ChromeOS. | ||
// | ||
// While early-boot experiments share a seed with non-early-boot experiments and | ||
// use the same code to load them from |local_state|, they do *not* share a safe | ||
// seed, since a seed could be safe for Chromium without being safe for | ||
// early-boot ChromeOS. | ||
class EarlyBootSeedStore : public VariationsSeedStore { | ||
public: | ||
// Construct an EarlyBootSeedStore, using |local_state| for the normal | ||
// seed and |safe_seed_details| (which may be nullopt if we are not in safe | ||
// seed mode) for the safe seed. | ||
EarlyBootSeedStore( | ||
PrefService* local_state, | ||
const absl::optional<featured::SeedDetails>& safe_seed_details); | ||
|
||
EarlyBootSeedStore(const EarlyBootSeedStore&) = delete; | ||
EarlyBootSeedStore& operator=(const EarlyBootSeedStore&) = delete; | ||
|
||
~EarlyBootSeedStore() override; | ||
|
||
// Populate the given |seed| and |client_state| with the safe seed state as | ||
// specified in the constructor. | ||
// Unlike the base class version, DOES NOT modify local state or have any side | ||
// effects. | ||
bool LoadSafeSeed(VariationsSeed* seed, | ||
ClientFilterableState* client_state) override; | ||
|
||
private: | ||
const absl::optional<featured::SeedDetails> safe_seed_details_; | ||
}; | ||
|
||
} // namespace variations::cros_early_boot::evaluate_seed | ||
|
||
#endif // COMPONENTS_VARIATIONS_CROS_EVALUATE_SEED_EARLY_BOOT_SEED_STORE_H_ |
124 changes: 124 additions & 0 deletions
124
components/variations/cros_evaluate_seed/early_boot_seed_store_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "components/variations/cros_evaluate_seed/early_boot_seed_store.h" | ||
|
||
#include <string> | ||
|
||
#include "base/test/scoped_command_line.h" | ||
#include "base/time/time.h" | ||
#include "chromeos/ash/components/dbus/featured/featured.pb.h" | ||
#include "components/prefs/testing_pref_service.h" | ||
#include "components/variations/client_filterable_state.h" | ||
#include "components/variations/proto/variations_seed.pb.h" | ||
#include "components/variations/variations_switches.h" | ||
#include "testing/gmock/include/gmock/gmock.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
namespace variations::cros_early_boot::evaluate_seed { | ||
|
||
namespace { | ||
|
||
MATCHER_P(EqualsProto, | ||
message, | ||
"Match a proto Message equal to the matcher's argument.") { | ||
std::string expected_serialized, actual_serialized; | ||
message.SerializeToString(&expected_serialized); | ||
arg.SerializeToString(&actual_serialized); | ||
return expected_serialized == actual_serialized; | ||
} | ||
|
||
// Populates |seed| with simple test data. The resulting seed will contain one | ||
// study called "test", which contains one experiment called "abc" with | ||
// probability weight 100. | ||
VariationsSeed CreateTestSeed() { | ||
VariationsSeed seed; | ||
Study* study = seed.add_study(); | ||
study->set_name("test"); | ||
study->set_default_experiment_name("abc"); | ||
Study_Experiment* experiment = study->add_experiment(); | ||
experiment->set_name("abc"); | ||
experiment->set_probability_weight(100); | ||
seed.set_serial_number("123"); | ||
return seed; | ||
} | ||
|
||
TEST(EarlyBootSeedStoreTest, LoadSafeSeed) { | ||
const VariationsSeed safe_seed = CreateTestSeed(); | ||
|
||
featured::SeedDetails safe_seed_details; | ||
safe_seed_details.set_date(123456789); | ||
safe_seed_details.set_locale("xx-YY"); | ||
safe_seed_details.set_permanent_consistency_country("us"); | ||
safe_seed_details.set_session_consistency_country("ca"); | ||
|
||
std::string serialized_seed; | ||
ASSERT_TRUE(safe_seed.SerializeToString(&serialized_seed)); | ||
safe_seed_details.set_compressed_data(serialized_seed); | ||
|
||
TestingPrefServiceSimple prefs; | ||
VariationsSeedStore::RegisterPrefs(prefs.registry()); | ||
|
||
// Allow empty signature. | ||
base::test::ScopedCommandLine scoped_command_line; | ||
scoped_command_line.GetProcessCommandLine()->AppendSwitch( | ||
switches::kAcceptEmptySeedSignatureForTesting); | ||
|
||
EarlyBootSeedStore store(&prefs, safe_seed_details); | ||
|
||
VariationsSeed actual_seed; | ||
ClientFilterableState actual_client_state( | ||
/*is_enterprise_function=*/base::BindOnce([] { return false; }), | ||
/*google_groups_function=*/base::BindOnce( | ||
[] { return base::flat_set<uint64_t>(); })); | ||
EXPECT_TRUE(store.LoadSafeSeed(&actual_seed, &actual_client_state)); | ||
|
||
EXPECT_THAT(actual_seed, EqualsProto(safe_seed)); | ||
EXPECT_EQ(base::Time::FromJavaTime(safe_seed_details.date()), | ||
actual_client_state.reference_date); | ||
EXPECT_EQ(safe_seed_details.locale(), actual_client_state.locale); | ||
EXPECT_EQ(safe_seed_details.permanent_consistency_country(), | ||
actual_client_state.permanent_consistency_country); | ||
EXPECT_EQ(safe_seed_details.session_consistency_country(), | ||
actual_client_state.session_consistency_country); | ||
} | ||
|
||
TEST(EarlyBootSeedStoreTest, LoadSafeSeed_Unspecified) { | ||
TestingPrefServiceSimple prefs; | ||
VariationsSeedStore::RegisterPrefs(prefs.registry()); | ||
|
||
EarlyBootSeedStore store(&prefs, absl::nullopt); | ||
VariationsSeed actual_seed; | ||
ClientFilterableState actual_client_state( | ||
/*is_enterprise_function=*/base::BindOnce([] { return false; }), | ||
/*google_groups_function=*/base::BindOnce( | ||
[] { return base::flat_set<uint64_t>(); })); | ||
EXPECT_DEATH(store.LoadSafeSeed(&actual_seed, &actual_client_state), | ||
"safe_seed_details_"); | ||
} | ||
|
||
TEST(EarlyBootSeedStoreTest, LoadSafeSeed_Invalid) { | ||
featured::SeedDetails safe_seed_details; | ||
safe_seed_details.set_compressed_data("bad"); | ||
|
||
TestingPrefServiceSimple prefs; | ||
VariationsSeedStore::RegisterPrefs(prefs.registry()); | ||
|
||
// Allow empty signature. | ||
base::test::ScopedCommandLine scoped_command_line; | ||
scoped_command_line.GetProcessCommandLine()->AppendSwitch( | ||
switches::kAcceptEmptySeedSignatureForTesting); | ||
|
||
EarlyBootSeedStore store(&prefs, safe_seed_details); | ||
|
||
VariationsSeed actual_seed; | ||
ClientFilterableState actual_client_state( | ||
/*is_enterprise_function=*/base::BindOnce([] { return false; }), | ||
/*google_groups_function=*/base::BindOnce( | ||
[] { return base::flat_set<uint64_t>(); })); | ||
EXPECT_FALSE(store.LoadSafeSeed(&actual_seed, &actual_client_state)); | ||
} | ||
|
||
} // namespace | ||
} // namespace variations::cros_early_boot::evaluate_seed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.