blob: 513998b727f277aae996165a606ddf5b53dd2be5 [file] [log] [blame]
[email protected]ae7bf342014-08-06 18:03:471// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dcheng4af48582016-04-19 00:29:355#include <memory>
[email protected]ae7bf342014-08-06 18:03:476#include <string>
7
blundell6e85b7c2015-09-29 12:33:358#include "base/base_switches.h"
[email protected]ae7bf342014-08-06 18:03:479#include "base/command_line.h"
[email protected]ae7bf342014-08-06 18:03:4710#include "base/files/file_path.h"
thestig18dfb7a52014-08-26 10:44:0411#include "base/files/file_util.h"
[email protected]ae7bf342014-08-06 18:03:4712#include "base/json/json_file_value_serializer.h"
a-v-y38416862016-12-08 08:40:1313#include "base/json/json_reader.h"
[email protected]ae7bf342014-08-06 18:03:4714#include "base/metrics/histogram_base.h"
15#include "base/metrics/histogram_samples.h"
16#include "base/metrics/statistics_recorder.h"
17#include "base/path_service.h"
[email protected]ae7bf342014-08-06 18:03:4718#include "base/strings/string_number_conversions.h"
19#include "base/strings/string_util.h"
a-v-y38416862016-12-08 08:40:1320#include "base/strings/utf_string_conversions.h"
[email protected]ae7bf342014-08-06 18:03:4721#include "base/values.h"
22#include "build/build_config.h"
23#include "chrome/browser/extensions/extension_browsertest.h"
24#include "chrome/browser/extensions/extension_service.h"
25#include "chrome/browser/prefs/chrome_pref_service_factory.h"
26#include "chrome/browser/prefs/profile_pref_store_manager.h"
27#include "chrome/browser/prefs/session_startup_pref.h"
28#include "chrome/browser/profiles/profile.h"
29#include "chrome/browser/ui/browser.h"
30#include "chrome/common/chrome_constants.h"
31#include "chrome/common/chrome_paths.h"
32#include "chrome/common/pref_names.h"
33#include "chrome/test/base/testing_profile.h"
34#include "components/search_engines/default_search_manager.h"
a-v-y38416862016-12-08 08:40:1335#include "components/search_engines/template_url_data.h"
[email protected]ae7bf342014-08-06 18:03:4736#include "extensions/browser/pref_names.h"
37#include "extensions/common/extension.h"
sammcfb473a872017-04-03 01:56:5938#include "services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h"
[email protected]ae7bf342014-08-06 18:03:4739
40#if defined(OS_CHROMEOS)
41#include "chromeos/chromeos_switches.h"
42#endif
43
proberge269fd092016-10-04 22:13:4144#if defined(OS_WIN)
45#include "base/test/test_reg_util_win.h"
46#endif
47
[email protected]ae7bf342014-08-06 18:03:4748namespace {
49
50// Extension ID of chrome/test/data/extensions/good.crx
51const char kGoodCrxId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
52
53// Explicit expectations from the caller of GetTrackedPrefHistogramCount(). This
54// enables detailed reporting of the culprit on failure.
55enum AllowedBuckets {
56 // Allow no samples in any buckets.
57 ALLOW_NONE = -1,
58 // Any integer between BEGIN_ALLOW_SINGLE_BUCKET and END_ALLOW_SINGLE_BUCKET
59 // indicates that only this specific bucket is allowed to have a sample.
60 BEGIN_ALLOW_SINGLE_BUCKET = 0,
61 END_ALLOW_SINGLE_BUCKET = 100,
62 // Allow any buckets (no extra verifications performed).
63 ALLOW_ANY
64};
65
proberge269fd092016-10-04 22:13:4166#if defined(OS_WIN)
67base::string16 GetRegistryPathForTestProfile() {
68 base::FilePath profile_dir;
69 EXPECT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &profile_dir));
70 return L"SOFTWARE\\Chromium\\PrefHashBrowserTest\\" +
71 profile_dir.BaseName().value();
72}
73#endif
74
[email protected]ae7bf342014-08-06 18:03:4775// Returns the number of times |histogram_name| was reported so far; adding the
76// results of the first 100 buckets (there are only ~19 reporting IDs as of this
77// writing; varies depending on the platform). |allowed_buckets| hints at extra
78// requirements verified in this method (see AllowedBuckets for details).
79int GetTrackedPrefHistogramCount(const char* histogram_name,
proberge269fd092016-10-04 22:13:4180 const char* histogram_suffix,
[email protected]ae7bf342014-08-06 18:03:4781 int allowed_buckets) {
proberge269fd092016-10-04 22:13:4182 std::string full_histogram_name(histogram_name);
83 if (*histogram_suffix)
84 full_histogram_name.append(".").append(histogram_suffix);
[email protected]ae7bf342014-08-06 18:03:4785 const base::HistogramBase* histogram =
proberge269fd092016-10-04 22:13:4186 base::StatisticsRecorder::FindHistogram(full_histogram_name);
[email protected]ae7bf342014-08-06 18:03:4787 if (!histogram)
88 return 0;
89
dcheng4af48582016-04-19 00:29:3590 std::unique_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
[email protected]ae7bf342014-08-06 18:03:4791 int sum = 0;
92 for (int i = 0; i < 100; ++i) {
93 int count_for_id = samples->GetCount(i);
94 EXPECT_GE(count_for_id, 0);
95 sum += count_for_id;
96
97 if (allowed_buckets == ALLOW_NONE ||
98 (allowed_buckets != ALLOW_ANY && i != allowed_buckets)) {
99 EXPECT_EQ(0, count_for_id) << "Unexpected reporting_id: " << i;
100 }
101 }
102 return sum;
103}
104
proberge269fd092016-10-04 22:13:41105// Helper function to call GetTrackedPrefHistogramCount with no external
106// validation suffix.
107int GetTrackedPrefHistogramCount(const char* histogram_name,
108 int allowed_buckets) {
109 return GetTrackedPrefHistogramCount(histogram_name, "", allowed_buckets);
110}
111
dcheng4af48582016-04-19 00:29:35112std::unique_ptr<base::DictionaryValue> ReadPrefsDictionary(
[email protected]ae7bf342014-08-06 18:03:47113 const base::FilePath& pref_file) {
prashhir54a994502015-03-05 09:30:57114 JSONFileValueDeserializer deserializer(pref_file);
115 int error_code = JSONFileValueDeserializer::JSON_NO_ERROR;
[email protected]ae7bf342014-08-06 18:03:47116 std::string error_str;
dcheng4af48582016-04-19 00:29:35117 std::unique_ptr<base::Value> prefs =
olli.raulaba045252015-10-16 06:16:40118 deserializer.Deserialize(&error_code, &error_str);
prashhir54a994502015-03-05 09:30:57119 if (!prefs || error_code != JSONFileValueDeserializer::JSON_NO_ERROR) {
[email protected]ae7bf342014-08-06 18:03:47120 ADD_FAILURE() << "Error #" << error_code << ": " << error_str;
dcheng4af48582016-04-19 00:29:35121 return std::unique_ptr<base::DictionaryValue>();
[email protected]ae7bf342014-08-06 18:03:47122 }
jdoerriedc72ee942016-12-07 15:43:28123 if (!prefs->IsType(base::Value::Type::DICTIONARY)) {
[email protected]ae7bf342014-08-06 18:03:47124 ADD_FAILURE();
dcheng4af48582016-04-19 00:29:35125 return std::unique_ptr<base::DictionaryValue>();
[email protected]ae7bf342014-08-06 18:03:47126 }
dcheng4af48582016-04-19 00:29:35127 return std::unique_ptr<base::DictionaryValue>(
[email protected]ae7bf342014-08-06 18:03:47128 static_cast<base::DictionaryValue*>(prefs.release()));
129}
130
proberge269fd092016-10-04 22:13:41131// Returns whether external validation is supported on the platform through
132// storing MACs in the registry.
133bool SupportsRegistryValidation() {
134#if defined(OS_WIN)
135 return true;
136#else
137 return false;
138#endif
139}
140
[email protected]ae7bf342014-08-06 18:03:47141#define PREF_HASH_BROWSER_TEST(fixture, test_name) \
142 IN_PROC_BROWSER_TEST_P(fixture, PRE_##test_name) { \
143 SetupPreferences(); \
144 } \
145 IN_PROC_BROWSER_TEST_P(fixture, test_name) { \
146 VerifyReactionToPrefAttack(); \
147 } \
148 INSTANTIATE_TEST_CASE_P( \
149 fixture##Instance, \
150 fixture, \
151 testing::Values( \
152 chrome_prefs::internals::kSettingsEnforcementGroupNoEnforcement, \
153 chrome_prefs::internals::kSettingsEnforcementGroupEnforceAlways, \
154 chrome_prefs::internals:: \
155 kSettingsEnforcementGroupEnforceAlwaysWithDSE, \
156 chrome_prefs::internals:: \
157 kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE));
158
159// A base fixture designed such that implementations do two things:
160// 1) Override all three pure-virtual methods below to setup, attack, and
161// verify preferenes throughout the tests provided by this fixture.
162// 2) Instantiate their test via the PREF_HASH_BROWSER_TEST macro above.
163// Based on top of ExtensionBrowserTest to allow easy interaction with the
164// ExtensionService.
165class PrefHashBrowserTestBase
166 : public ExtensionBrowserTest,
167 public testing::WithParamInterface<std::string> {
168 public:
169 // List of potential protection levels for this test in strict increasing
170 // order of protection levels.
171 enum SettingsProtectionLevel {
172 PROTECTION_DISABLED_ON_PLATFORM,
173 PROTECTION_DISABLED_FOR_GROUP,
174 PROTECTION_ENABLED_BASIC,
175 PROTECTION_ENABLED_DSE,
176 PROTECTION_ENABLED_EXTENSIONS,
177 // Represents the strongest level (i.e. always equivalent to the last one in
178 // terms of protection), leave this one last when adding new levels.
179 PROTECTION_ENABLED_ALL
180 };
181
182 PrefHashBrowserTestBase()
183 : protection_level_(GetProtectionLevelFromTrialGroup(GetParam())) {
184 }
185
avi556c05022014-12-22 23:31:43186 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]ae7bf342014-08-06 18:03:47187 ExtensionBrowserTest::SetUpCommandLine(command_line);
188 EXPECT_FALSE(command_line->HasSwitch(switches::kForceFieldTrials));
189 command_line->AppendSwitchASCII(
190 switches::kForceFieldTrials,
191 std::string(chrome_prefs::internals::kSettingsEnforcementTrialName) +
192 "/" + GetParam() + "/");
193#if defined(OS_CHROMEOS)
194 command_line->AppendSwitch(
195 chromeos::switches::kIgnoreUserProfileMappingForTests);
196#endif
197 }
198
dcheng8f4b8622014-10-23 16:37:48199 bool SetUpUserDataDirectory() override {
[email protected]ae7bf342014-08-06 18:03:47200 // Do the normal setup in the PRE test and attack preferences in the main
201 // test.
202 if (IsPRETest())
203 return ExtensionBrowserTest::SetUpUserDataDirectory();
204
205#if defined(OS_CHROMEOS)
206 // For some reason, the Preferences file does not exist in the location
207 // below on Chrome OS. Since protection is disabled on Chrome OS, it's okay
208 // to simply not attack preferences at all (and still assert that no
209 // hardening related histogram kicked in in VerifyReactionToPrefAttack()).
210 // TODO(gab): Figure out why there is no Preferences file in this location
211 // on Chrome OS (and re-enable the section disabled for OS_CHROMEOS further
212 // below).
213 EXPECT_EQ(PROTECTION_DISABLED_ON_PLATFORM, protection_level_);
214 return true;
215#endif
216
217 base::FilePath profile_dir;
218 EXPECT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &profile_dir));
219 profile_dir = profile_dir.AppendASCII(TestingProfile::kTestUserProfileDir);
220
221 // Sanity check that old protected pref file is never present in modern
222 // Chromes.
223 EXPECT_FALSE(base::PathExists(
sammcf420c16e2017-03-16 02:11:13224 profile_dir.Append(FILE_PATH_LITERAL("Protected Preferences"))));
[email protected]ae7bf342014-08-06 18:03:47225
226 // Read the preferences from disk.
227
228 const base::FilePath unprotected_pref_file =
229 profile_dir.Append(chrome::kPreferencesFilename);
230 EXPECT_TRUE(base::PathExists(unprotected_pref_file));
231
232 const base::FilePath protected_pref_file =
233 profile_dir.Append(chrome::kSecurePreferencesFilename);
234 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM,
235 base::PathExists(protected_pref_file));
236
dcheng4af48582016-04-19 00:29:35237 std::unique_ptr<base::DictionaryValue> unprotected_preferences(
[email protected]ae7bf342014-08-06 18:03:47238 ReadPrefsDictionary(unprotected_pref_file));
239 if (!unprotected_preferences)
240 return false;
241
dcheng4af48582016-04-19 00:29:35242 std::unique_ptr<base::DictionaryValue> protected_preferences;
[email protected]ae7bf342014-08-06 18:03:47243 if (protection_level_ > PROTECTION_DISABLED_ON_PLATFORM) {
244 protected_preferences = ReadPrefsDictionary(protected_pref_file);
245 if (!protected_preferences)
246 return false;
247 }
248
249 // Let the underlying test modify the preferences.
250 AttackPreferencesOnDisk(unprotected_preferences.get(),
251 protected_preferences.get());
252
253 // Write the modified preferences back to disk.
254
255 JSONFileValueSerializer unprotected_prefs_serializer(unprotected_pref_file);
256 EXPECT_TRUE(
257 unprotected_prefs_serializer.Serialize(*unprotected_preferences));
258
259 if (protected_preferences) {
260 JSONFileValueSerializer protected_prefs_serializer(protected_pref_file);
261 EXPECT_TRUE(protected_prefs_serializer.Serialize(*protected_preferences));
262 }
263
264 return true;
265 }
266
gabbcdefd0cc2015-02-17 18:12:40267 void SetUpInProcessBrowserTestFixture() override {
268 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
269
270 // Bots are on a domain, turn off the domain check for settings hardening in
271 // order to be able to test all SettingsEnforcement groups.
272 chrome_prefs::DisableDomainCheckForTesting();
proberge269fd092016-10-04 22:13:41273
274#if defined(OS_WIN)
275 // Avoid polluting prefs for the user and the bots by writing to a specific
276 // testing registry path.
277 registry_key_for_external_validation_ = GetRegistryPathForTestProfile();
278 ProfilePrefStoreManager::SetPreferenceValidationRegistryPathForTesting(
279 &registry_key_for_external_validation_);
280
281 // Keys should be unique, but to avoid flakes in the long run make sure an
282 // identical test key wasn't left behind by a previous test.
283 if (IsPRETest()) {
284 base::win::RegKey key;
285 if (key.Open(HKEY_CURRENT_USER,
286 registry_key_for_external_validation_.c_str(),
287 KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
288 LONG result = key.DeleteKey(L"");
289 ASSERT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
290 }
291 }
292#endif
293 }
294
295 void TearDown() override {
296#if defined(OS_WIN)
297 // When done, delete the Registry key to avoid polluting the registry.
298 // TODO(proberge): it would be nice to delete keys from interrupted tests
299 // as well.
300 if (!IsPRETest()) {
301 base::string16 registry_key = GetRegistryPathForTestProfile();
302 base::win::RegKey key;
303 if (key.Open(HKEY_CURRENT_USER, registry_key.c_str(),
304 KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
305 LONG result = key.DeleteKey(L"");
306 ASSERT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
307 }
308 }
309#endif
310 ExtensionBrowserTest::TearDown();
gabbcdefd0cc2015-02-17 18:12:40311 }
312
[email protected]ae7bf342014-08-06 18:03:47313 // In the PRE_ test, find the number of tracked preferences that were
314 // initialized and save it to a file to be read back in the main test and used
315 // as the total number of tracked preferences.
dcheng8f4b8622014-10-23 16:37:48316 void SetUpOnMainThread() override {
[email protected]ae7bf342014-08-06 18:03:47317 ExtensionBrowserTest::SetUpOnMainThread();
318
319 // File in which the PRE_ test will save the number of tracked preferences
320 // on this platform.
321 const char kNumTrackedPrefFilename[] = "NumTrackedPrefs";
322
323 base::FilePath num_tracked_prefs_file;
324 ASSERT_TRUE(
325 PathService::Get(chrome::DIR_USER_DATA, &num_tracked_prefs_file));
326 num_tracked_prefs_file =
327 num_tracked_prefs_file.AppendASCII(kNumTrackedPrefFilename);
328
329 if (IsPRETest()) {
330 num_tracked_prefs_ = GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43331 user_prefs::tracked::kTrackedPrefHistogramNullInitialized, ALLOW_ANY);
[email protected]ae7bf342014-08-06 18:03:47332 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM,
333 num_tracked_prefs_ > 0);
334
gab342aa6182014-10-02 21:59:00335 // Split tracked prefs are reported as Unchanged not as NullInitialized
[email protected]ae7bf342014-08-06 18:03:47336 // when an empty dictionary is encountered on first run (this should only
337 // hit for pref #5 in the current design).
338 int num_split_tracked_prefs = GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43339 user_prefs::tracked::kTrackedPrefHistogramUnchanged,
340 BEGIN_ALLOW_SINGLE_BUCKET + 5);
[email protected]ae7bf342014-08-06 18:03:47341 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
342 num_split_tracked_prefs);
343
proberge269fd092016-10-04 22:13:41344 if (SupportsRegistryValidation()) {
345 // Same checks as above, but for the registry.
346 num_tracked_prefs_ = GetTrackedPrefHistogramCount(
347 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
348 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
349 ALLOW_ANY);
350 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM,
351 num_tracked_prefs_ > 0);
352
353 int num_split_tracked_prefs = GetTrackedPrefHistogramCount(
354 user_prefs::tracked::kTrackedPrefHistogramUnchanged,
355 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
356 BEGIN_ALLOW_SINGLE_BUCKET + 5);
357 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
358 num_split_tracked_prefs);
359 }
360
[email protected]ae7bf342014-08-06 18:03:47361 num_tracked_prefs_ += num_split_tracked_prefs;
362
363 std::string num_tracked_prefs_str = base::IntToString(num_tracked_prefs_);
364 EXPECT_EQ(static_cast<int>(num_tracked_prefs_str.size()),
365 base::WriteFile(num_tracked_prefs_file,
366 num_tracked_prefs_str.c_str(),
367 num_tracked_prefs_str.size()));
368 } else {
369 std::string num_tracked_prefs_str;
370 EXPECT_TRUE(base::ReadFileToString(num_tracked_prefs_file,
371 &num_tracked_prefs_str));
372 EXPECT_TRUE(
373 base::StringToInt(num_tracked_prefs_str, &num_tracked_prefs_));
374 }
375 }
376
377 protected:
378 // Called from the PRE_ test's body. Overrides should use it to setup
379 // preferences through Chrome.
380 virtual void SetupPreferences() = 0;
381
382 // Called prior to the main test launching its browser. Overrides should use
383 // it to attack preferences. |(un)protected_preferences| represent the state
384 // on disk prior to launching the main test, they can be modified by this
385 // method and modifications will be flushed back to disk before launching the
386 // main test. |unprotected_preferences| is never NULL, |protected_preferences|
387 // may be NULL if in PROTECTION_DISABLED_ON_PLATFORM mode.
388 virtual void AttackPreferencesOnDisk(
389 base::DictionaryValue* unprotected_preferences,
390 base::DictionaryValue* protected_preferences) = 0;
391
392 // Called from the body of the main test. Overrides should use it to verify
393 // that the browser had the desired reaction when faced when the attack
394 // orchestrated in AttackPreferencesOnDisk().
395 virtual void VerifyReactionToPrefAttack() = 0;
396
397 int num_tracked_prefs() const { return num_tracked_prefs_; }
398
399 const SettingsProtectionLevel protection_level_;
400
401 private:
402 // Returns true if this is the PRE_ phase of the test.
403 bool IsPRETest() {
brettw66d1b81b2015-07-06 19:29:40404 return base::StartsWith(
brettw44ce0ec52015-06-12 01:57:57405 testing::UnitTest::GetInstance()->current_test_info()->name(), "PRE_",
brettw66d1b81b2015-07-06 19:29:40406 base::CompareCase::SENSITIVE);
[email protected]ae7bf342014-08-06 18:03:47407 }
408
409 SettingsProtectionLevel GetProtectionLevelFromTrialGroup(
410 const std::string& trial_group) {
411 if (!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking)
412 return PROTECTION_DISABLED_ON_PLATFORM;
413
414// Protection levels can't be adjusted via --force-fieldtrials in official
415// builds.
416#if defined(OFFICIAL_BUILD)
417
418#if defined(OS_WIN)
419 // The strongest mode is enforced on Windows in the absence of a field
420 // trial.
421 return PROTECTION_ENABLED_ALL;
422#else
423 return PROTECTION_DISABLED_FOR_GROUP;
424#endif
425
426#else // defined(OFFICIAL_BUILD)
427
428 using namespace chrome_prefs::internals;
429 if (trial_group == kSettingsEnforcementGroupNoEnforcement) {
430 return PROTECTION_DISABLED_FOR_GROUP;
431 } else if (trial_group == kSettingsEnforcementGroupEnforceAlways) {
432 return PROTECTION_ENABLED_BASIC;
433 } else if (trial_group == kSettingsEnforcementGroupEnforceAlwaysWithDSE) {
434 return PROTECTION_ENABLED_DSE;
435 } else if (trial_group ==
436 kSettingsEnforcementGroupEnforceAlwaysWithExtensionsAndDSE) {
437 return PROTECTION_ENABLED_EXTENSIONS;
438 } else {
439 ADD_FAILURE();
440 return static_cast<SettingsProtectionLevel>(-1);
441 }
442
443#endif // defined(OFFICIAL_BUILD)
444
445 }
446
447 int num_tracked_prefs_;
proberge269fd092016-10-04 22:13:41448
449#if defined(OS_WIN)
450 base::string16 registry_key_for_external_validation_;
451#endif
[email protected]ae7bf342014-08-06 18:03:47452};
453
454} // namespace
455
456// Verifies that nothing is reset when nothing is tampered with.
457// Also sanity checks that the expected preferences files are in place.
458class PrefHashBrowserTestUnchangedDefault : public PrefHashBrowserTestBase {
459 public:
dcheng8f4b8622014-10-23 16:37:48460 void SetupPreferences() override {
[email protected]ae7bf342014-08-06 18:03:47461 // Default Chrome setup.
462 }
463
dcheng8f4b8622014-10-23 16:37:48464 void AttackPreferencesOnDisk(
[email protected]ae7bf342014-08-06 18:03:47465 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:17466 base::DictionaryValue* protected_preferences) override {
[email protected]ae7bf342014-08-06 18:03:47467 // No attack.
468 }
469
dcheng8f4b8622014-10-23 16:37:48470 void VerifyReactionToPrefAttack() override {
[email protected]ae7bf342014-08-06 18:03:47471 // Expect all prefs to be reported as Unchanged with no resets.
deepak.m113481c82015-12-16 05:21:43472 EXPECT_EQ(
473 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
474 ? num_tracked_prefs()
475 : 0,
476 GetTrackedPrefHistogramCount(
477 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
478 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
479 user_prefs::tracked::kTrackedPrefHistogramWantedReset,
480 ALLOW_NONE));
[email protected]ae7bf342014-08-06 18:03:47481 EXPECT_EQ(0,
482 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43483 user_prefs::tracked::kTrackedPrefHistogramReset, ALLOW_NONE));
[email protected]ae7bf342014-08-06 18:03:47484
485 // Nothing else should have triggered.
[email protected]ae7bf342014-08-06 18:03:47486 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43487 0, GetTrackedPrefHistogramCount(
488 user_prefs::tracked::kTrackedPrefHistogramChanged, ALLOW_NONE));
489 EXPECT_EQ(
490 0, GetTrackedPrefHistogramCount(
491 user_prefs::tracked::kTrackedPrefHistogramCleared, ALLOW_NONE));
492 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
493 user_prefs::tracked::kTrackedPrefHistogramInitialized,
494 ALLOW_NONE));
495 EXPECT_EQ(0,
496 GetTrackedPrefHistogramCount(
497 user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
498 ALLOW_NONE));
499 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
500 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
501 ALLOW_NONE));
502 EXPECT_EQ(
503 0, GetTrackedPrefHistogramCount(
504 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
505 ALLOW_NONE));
proberge269fd092016-10-04 22:13:41506
507 if (SupportsRegistryValidation()) {
508 // Expect all prefs to be reported as Unchanged.
509 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
510 ? num_tracked_prefs()
511 : 0,
512 GetTrackedPrefHistogramCount(
513 user_prefs::tracked::kTrackedPrefHistogramUnchanged,
514 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
515 ALLOW_ANY));
516 }
[email protected]ae7bf342014-08-06 18:03:47517 }
518};
519
520PREF_HASH_BROWSER_TEST(PrefHashBrowserTestUnchangedDefault, UnchangedDefault);
521
522// Augments PrefHashBrowserTestUnchangedDefault to confirm that nothing is reset
523// when nothing is tampered with, even if Chrome itself wrote custom prefs in
524// its last run.
525class PrefHashBrowserTestUnchangedCustom
526 : public PrefHashBrowserTestUnchangedDefault {
527 public:
dcheng8f4b8622014-10-23 16:37:48528 void SetupPreferences() override {
[email protected]ae7bf342014-08-06 18:03:47529 profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com");
530
531 InstallExtensionWithUIAutoConfirm(
532 test_data_dir_.AppendASCII("good.crx"), 1, browser());
533 }
534
dcheng8f4b8622014-10-23 16:37:48535 void VerifyReactionToPrefAttack() override {
[email protected]ae7bf342014-08-06 18:03:47536 // Make sure the settings written in the last run stuck.
537 EXPECT_EQ("http://example.com",
538 profile()->GetPrefs()->GetString(prefs::kHomePage));
539
540 EXPECT_TRUE(extension_service()->GetExtensionById(kGoodCrxId, false));
541
542 // Reaction should be identical to unattacked default prefs.
543 PrefHashBrowserTestUnchangedDefault::VerifyReactionToPrefAttack();
544 }
545};
546
547PREF_HASH_BROWSER_TEST(PrefHashBrowserTestUnchangedCustom, UnchangedCustom);
548
549// Verifies that cleared prefs are reported.
550class PrefHashBrowserTestClearedAtomic : public PrefHashBrowserTestBase {
551 public:
dcheng8f4b8622014-10-23 16:37:48552 void SetupPreferences() override {
[email protected]ae7bf342014-08-06 18:03:47553 profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com");
554 }
555
dcheng8f4b8622014-10-23 16:37:48556 void AttackPreferencesOnDisk(
[email protected]ae7bf342014-08-06 18:03:47557 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:17558 base::DictionaryValue* protected_preferences) override {
[email protected]ae7bf342014-08-06 18:03:47559 base::DictionaryValue* selected_prefs =
560 protection_level_ >= PROTECTION_ENABLED_BASIC ? protected_preferences
561 : unprotected_preferences;
562 // |selected_prefs| should never be NULL under the protection level picking
563 // it.
564 EXPECT_TRUE(selected_prefs);
565 EXPECT_TRUE(selected_prefs->Remove(prefs::kHomePage, NULL));
566 }
567
dcheng8f4b8622014-10-23 16:37:48568 void VerifyReactionToPrefAttack() override {
[email protected]ae7bf342014-08-06 18:03:47569 // The clearance of homepage should have been noticed (as pref #2 being
570 // cleared), but shouldn't have triggered a reset (as there is nothing we
571 // can do when the pref is already gone).
572 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
[email protected]ae7bf342014-08-06 18:03:47573 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43574 user_prefs::tracked::kTrackedPrefHistogramCleared,
575 BEGIN_ALLOW_SINGLE_BUCKET + 2));
576 EXPECT_EQ(
577 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
578 ? num_tracked_prefs() - 1
579 : 0,
580 GetTrackedPrefHistogramCount(
581 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
582 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
583 user_prefs::tracked::kTrackedPrefHistogramWantedReset,
584 ALLOW_NONE));
[email protected]ae7bf342014-08-06 18:03:47585 EXPECT_EQ(0,
586 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43587 user_prefs::tracked::kTrackedPrefHistogramReset, ALLOW_NONE));
[email protected]ae7bf342014-08-06 18:03:47588
589 // Nothing else should have triggered.
[email protected]ae7bf342014-08-06 18:03:47590 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43591 0, GetTrackedPrefHistogramCount(
592 user_prefs::tracked::kTrackedPrefHistogramChanged, ALLOW_NONE));
593 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
594 user_prefs::tracked::kTrackedPrefHistogramInitialized,
595 ALLOW_NONE));
596 EXPECT_EQ(0,
597 GetTrackedPrefHistogramCount(
598 user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
599 ALLOW_NONE));
600 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
601 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
602 ALLOW_NONE));
603 EXPECT_EQ(
604 0, GetTrackedPrefHistogramCount(
605 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
606 ALLOW_NONE));
proberge269fd092016-10-04 22:13:41607
608 if (SupportsRegistryValidation()) {
609 // Expect homepage clearance to have been noticed by registry validation.
610 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
611 GetTrackedPrefHistogramCount(
612 user_prefs::tracked::kTrackedPrefHistogramCleared,
613 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
614 BEGIN_ALLOW_SINGLE_BUCKET + 2));
615 }
[email protected]ae7bf342014-08-06 18:03:47616 }
617};
618
619PREF_HASH_BROWSER_TEST(PrefHashBrowserTestClearedAtomic, ClearedAtomic);
620
621// Verifies that clearing the MACs results in untrusted Initialized pings for
622// non-null protected prefs.
623class PrefHashBrowserTestUntrustedInitialized : public PrefHashBrowserTestBase {
624 public:
dcheng8f4b8622014-10-23 16:37:48625 void SetupPreferences() override {
[email protected]ae7bf342014-08-06 18:03:47626 // Explicitly set the DSE (it's otherwise NULL by default, preventing
627 // thorough testing of the PROTECTION_ENABLED_DSE level).
628 DefaultSearchManager default_search_manager(
629 profile()->GetPrefs(), DefaultSearchManager::ObserverCallback());
630 DefaultSearchManager::Source dse_source =
631 static_cast<DefaultSearchManager::Source>(-1);
632
633 const TemplateURLData* default_template_url_data =
634 default_search_manager.GetDefaultSearchEngine(&dse_source);
635 EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, dse_source);
636
637 default_search_manager.SetUserSelectedDefaultSearchEngine(
638 *default_template_url_data);
639
640 default_search_manager.GetDefaultSearchEngine(&dse_source);
641 EXPECT_EQ(DefaultSearchManager::FROM_USER, dse_source);
642
643 // Also explicitly set an atomic pref that falls under
644 // PROTECTION_ENABLED_BASIC.
645 profile()->GetPrefs()->SetInteger(prefs::kRestoreOnStartup,
646 SessionStartupPref::URLS);
647 }
648
dcheng8f4b8622014-10-23 16:37:48649 void AttackPreferencesOnDisk(
[email protected]ae7bf342014-08-06 18:03:47650 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:17651 base::DictionaryValue* protected_preferences) override {
proberge574d7d92016-08-01 20:14:11652 unprotected_preferences->Remove("protection.macs", NULL);
[email protected]ae7bf342014-08-06 18:03:47653 if (protected_preferences)
proberge574d7d92016-08-01 20:14:11654 protected_preferences->Remove("protection.macs", NULL);
[email protected]ae7bf342014-08-06 18:03:47655 }
656
dcheng8f4b8622014-10-23 16:37:48657 void VerifyReactionToPrefAttack() override {
gab342aa6182014-10-02 21:59:00658 // Preferences that are NULL by default will be NullInitialized.
[email protected]ae7bf342014-08-06 18:03:47659 int num_null_values = GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43660 user_prefs::tracked::kTrackedPrefHistogramNullInitialized, ALLOW_ANY);
[email protected]ae7bf342014-08-06 18:03:47661 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM,
662 num_null_values > 0);
663 if (num_null_values > 0) {
664 // This test requires that at least 3 prefs be non-null (extensions, DSE,
665 // and 1 atomic pref explictly set for this test above).
gab342aa6182014-10-02 21:59:00666 EXPECT_GE(num_tracked_prefs() - num_null_values, 3);
[email protected]ae7bf342014-08-06 18:03:47667 }
668
669 // Expect all non-null prefs to be reported as Initialized (with
670 // accompanying resets or wanted resets based on the current protection
671 // level).
deepak.m113481c82015-12-16 05:21:43672 EXPECT_EQ(
673 num_tracked_prefs() - num_null_values,
674 GetTrackedPrefHistogramCount(
675 user_prefs::tracked::kTrackedPrefHistogramInitialized, ALLOW_ANY));
[email protected]ae7bf342014-08-06 18:03:47676
677 int num_protected_prefs = 0;
678 // A switch statement falling through each protection level in decreasing
679 // levels of protection to add expectations for each level which augments
680 // the previous one.
681 switch (protection_level_) {
682 case PROTECTION_ENABLED_ALL:
683 // Falls through.
684 case PROTECTION_ENABLED_EXTENSIONS:
685 ++num_protected_prefs;
686 // Falls through.
687 case PROTECTION_ENABLED_DSE:
688 ++num_protected_prefs;
689 // Falls through.
690 case PROTECTION_ENABLED_BASIC:
691 num_protected_prefs += num_tracked_prefs() - num_null_values - 2;
692 // Falls through.
693 case PROTECTION_DISABLED_FOR_GROUP:
694 // No protection. Falls through.
695 case PROTECTION_DISABLED_ON_PLATFORM:
696 // No protection.
697 break;
698 }
699
deepak.m113481c82015-12-16 05:21:43700 EXPECT_EQ(
701 num_tracked_prefs() - num_null_values - num_protected_prefs,
702 GetTrackedPrefHistogramCount(
703 user_prefs::tracked::kTrackedPrefHistogramWantedReset, ALLOW_ANY));
[email protected]ae7bf342014-08-06 18:03:47704 EXPECT_EQ(num_protected_prefs,
deepak.m113481c82015-12-16 05:21:43705 GetTrackedPrefHistogramCount(
706 user_prefs::tracked::kTrackedPrefHistogramReset, ALLOW_ANY));
[email protected]ae7bf342014-08-06 18:03:47707
708 // Explicitly verify the result of reported resets.
709
710 DefaultSearchManager default_search_manager(
711 profile()->GetPrefs(), DefaultSearchManager::ObserverCallback());
712 DefaultSearchManager::Source dse_source =
713 static_cast<DefaultSearchManager::Source>(-1);
714 default_search_manager.GetDefaultSearchEngine(&dse_source);
715 EXPECT_EQ(protection_level_ < PROTECTION_ENABLED_DSE
716 ? DefaultSearchManager::FROM_USER
717 : DefaultSearchManager::FROM_FALLBACK,
718 dse_source);
719
720 EXPECT_EQ(protection_level_ < PROTECTION_ENABLED_BASIC,
721 profile()->GetPrefs()->GetInteger(prefs::kRestoreOnStartup) ==
722 SessionStartupPref::URLS);
723
724 // Nothing else should have triggered.
deepak.m113481c82015-12-16 05:21:43725 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
726 user_prefs::tracked::kTrackedPrefHistogramUnchanged,
727 ALLOW_NONE));
[email protected]ae7bf342014-08-06 18:03:47728 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43729 0, GetTrackedPrefHistogramCount(
730 user_prefs::tracked::kTrackedPrefHistogramChanged, ALLOW_NONE));
731 EXPECT_EQ(
732 0, GetTrackedPrefHistogramCount(
733 user_prefs::tracked::kTrackedPrefHistogramCleared, ALLOW_NONE));
734 EXPECT_EQ(
735 0, GetTrackedPrefHistogramCount(
736 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
737 ALLOW_NONE));
proberge269fd092016-10-04 22:13:41738
739 if (SupportsRegistryValidation()) {
740 // The MACs have been cleared but the preferences have not been tampered.
741 // The registry should report all prefs as unchanged.
742 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
743 ? num_tracked_prefs()
744 : 0,
745 GetTrackedPrefHistogramCount(
746 user_prefs::tracked::kTrackedPrefHistogramUnchanged,
747 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
748 ALLOW_ANY));
749 }
[email protected]ae7bf342014-08-06 18:03:47750 }
751};
752
753PREF_HASH_BROWSER_TEST(PrefHashBrowserTestUntrustedInitialized,
754 UntrustedInitialized);
755
756// Verifies that changing an atomic pref results in it being reported (and reset
757// if the protection level allows it).
758class PrefHashBrowserTestChangedAtomic : public PrefHashBrowserTestBase {
759 public:
dcheng8f4b8622014-10-23 16:37:48760 void SetupPreferences() override {
[email protected]ae7bf342014-08-06 18:03:47761 profile()->GetPrefs()->SetInteger(prefs::kRestoreOnStartup,
762 SessionStartupPref::URLS);
763
764 ListPrefUpdate update(profile()->GetPrefs(),
765 prefs::kURLsToRestoreOnStartup);
766 update->AppendString("http://example.com");
767 }
768
dcheng8f4b8622014-10-23 16:37:48769 void AttackPreferencesOnDisk(
[email protected]ae7bf342014-08-06 18:03:47770 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:17771 base::DictionaryValue* protected_preferences) override {
[email protected]ae7bf342014-08-06 18:03:47772 base::DictionaryValue* selected_prefs =
773 protection_level_ >= PROTECTION_ENABLED_BASIC ? protected_preferences
774 : unprotected_preferences;
775 // |selected_prefs| should never be NULL under the protection level picking
776 // it.
777 EXPECT_TRUE(selected_prefs);
778 base::ListValue* startup_urls;
779 EXPECT_TRUE(
780 selected_prefs->GetList(prefs::kURLsToRestoreOnStartup, &startup_urls));
781 EXPECT_TRUE(startup_urls);
782 EXPECT_EQ(1U, startup_urls->GetSize());
783 startup_urls->AppendString("http://example.org");
784 }
785
dcheng8f4b8622014-10-23 16:37:48786 void VerifyReactionToPrefAttack() override {
[email protected]ae7bf342014-08-06 18:03:47787 // Expect a single Changed event for tracked pref #4 (startup URLs).
788 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
[email protected]ae7bf342014-08-06 18:03:47789 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43790 user_prefs::tracked::kTrackedPrefHistogramChanged,
791 BEGIN_ALLOW_SINGLE_BUCKET + 4));
[email protected]ae7bf342014-08-06 18:03:47792 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43793 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
794 ? num_tracked_prefs() - 1
795 : 0,
796 GetTrackedPrefHistogramCount(
797 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
798
799 EXPECT_EQ((protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
800 protection_level_ < PROTECTION_ENABLED_BASIC)
801 ? 1
802 : 0,
803 GetTrackedPrefHistogramCount(
804 user_prefs::tracked::kTrackedPrefHistogramWantedReset,
805 BEGIN_ALLOW_SINGLE_BUCKET + 4));
[email protected]ae7bf342014-08-06 18:03:47806 EXPECT_EQ(protection_level_ >= PROTECTION_ENABLED_BASIC ? 1 : 0,
deepak.m113481c82015-12-16 05:21:43807 GetTrackedPrefHistogramCount(
808 user_prefs::tracked::kTrackedPrefHistogramReset,
809 BEGIN_ALLOW_SINGLE_BUCKET + 4));
[email protected]ae7bf342014-08-06 18:03:47810
811// TODO(gab): This doesn't work on OS_CHROMEOS because we fail to attack
812// Preferences.
813#if !defined(OS_CHROMEOS)
814 // Explicitly verify the result of reported resets.
815 EXPECT_EQ(protection_level_ >= PROTECTION_ENABLED_BASIC ? 0U : 2U,
816 profile()
817 ->GetPrefs()
818 ->GetList(prefs::kURLsToRestoreOnStartup)
819 ->GetSize());
820#endif
821
822 // Nothing else should have triggered.
[email protected]ae7bf342014-08-06 18:03:47823 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43824 0, GetTrackedPrefHistogramCount(
825 user_prefs::tracked::kTrackedPrefHistogramCleared, ALLOW_NONE));
826 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
827 user_prefs::tracked::kTrackedPrefHistogramInitialized,
828 ALLOW_NONE));
829 EXPECT_EQ(0,
830 GetTrackedPrefHistogramCount(
831 user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
832 ALLOW_NONE));
833 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
834 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
835 ALLOW_NONE));
836 EXPECT_EQ(
837 0, GetTrackedPrefHistogramCount(
838 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
839 ALLOW_NONE));
proberge269fd092016-10-04 22:13:41840
841 if (SupportsRegistryValidation()) {
842 // Expect a single Changed event for tracked pref #4 (startup URLs).
843 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
844 GetTrackedPrefHistogramCount(
845 user_prefs::tracked::kTrackedPrefHistogramChanged,
846 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
847 BEGIN_ALLOW_SINGLE_BUCKET + 4));
848 }
[email protected]ae7bf342014-08-06 18:03:47849 }
850};
851
852PREF_HASH_BROWSER_TEST(PrefHashBrowserTestChangedAtomic, ChangedAtomic);
853
854// Verifies that changing or adding an entry in a split pref results in both
855// items being reported (and remove if the protection level allows it).
856class PrefHashBrowserTestChangedSplitPref : public PrefHashBrowserTestBase {
857 public:
dcheng8f4b8622014-10-23 16:37:48858 void SetupPreferences() override {
[email protected]ae7bf342014-08-06 18:03:47859 InstallExtensionWithUIAutoConfirm(
860 test_data_dir_.AppendASCII("good.crx"), 1, browser());
861 }
862
dcheng8f4b8622014-10-23 16:37:48863 void AttackPreferencesOnDisk(
[email protected]ae7bf342014-08-06 18:03:47864 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:17865 base::DictionaryValue* protected_preferences) override {
[email protected]ae7bf342014-08-06 18:03:47866 base::DictionaryValue* selected_prefs =
867 protection_level_ >= PROTECTION_ENABLED_EXTENSIONS
868 ? protected_preferences
869 : unprotected_preferences;
870 // |selected_prefs| should never be NULL under the protection level picking
871 // it.
872 EXPECT_TRUE(selected_prefs);
873 base::DictionaryValue* extensions_dict;
874 EXPECT_TRUE(selected_prefs->GetDictionary(
875 extensions::pref_names::kExtensions, &extensions_dict));
876 EXPECT_TRUE(extensions_dict);
877
878 // Tamper with any installed setting for good.crx
879 base::DictionaryValue* good_crx_dict;
880 EXPECT_TRUE(extensions_dict->GetDictionary(kGoodCrxId, &good_crx_dict));
881 int good_crx_state;
882 EXPECT_TRUE(good_crx_dict->GetInteger("state", &good_crx_state));
883 EXPECT_EQ(extensions::Extension::ENABLED, good_crx_state);
884 good_crx_dict->SetInteger("state", extensions::Extension::DISABLED);
885
886 // Drop a fake extension (for the purpose of this test, dropped settings
887 // don't need to be valid extension settings).
888 base::DictionaryValue* fake_extension = new base::DictionaryValue;
889 fake_extension->SetString("name", "foo");
890 extensions_dict->Set(std::string(32, 'a'), fake_extension);
891 }
892
dcheng8f4b8622014-10-23 16:37:48893 void VerifyReactionToPrefAttack() override {
[email protected]ae7bf342014-08-06 18:03:47894 // Expect a single split pref changed report with a count of 2 for tracked
895 // pref #5 (extensions).
896 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
deepak.m113481c82015-12-16 05:21:43897 GetTrackedPrefHistogramCount(
898 user_prefs::tracked::kTrackedPrefHistogramChanged,
899 BEGIN_ALLOW_SINGLE_BUCKET + 5));
[email protected]ae7bf342014-08-06 18:03:47900 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
901 GetTrackedPrefHistogramCount(
902 "Settings.TrackedSplitPreferenceChanged.extensions.settings",
903 BEGIN_ALLOW_SINGLE_BUCKET + 2));
904
905 // Everything else should have remained unchanged.
[email protected]ae7bf342014-08-06 18:03:47906 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43907 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
908 ? num_tracked_prefs() - 1
909 : 0,
910 GetTrackedPrefHistogramCount(
911 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
912
913 EXPECT_EQ((protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
914 protection_level_ < PROTECTION_ENABLED_EXTENSIONS)
915 ? 1
916 : 0,
917 GetTrackedPrefHistogramCount(
918 user_prefs::tracked::kTrackedPrefHistogramWantedReset,
919 BEGIN_ALLOW_SINGLE_BUCKET + 5));
[email protected]ae7bf342014-08-06 18:03:47920 EXPECT_EQ(protection_level_ >= PROTECTION_ENABLED_EXTENSIONS ? 1 : 0,
deepak.m113481c82015-12-16 05:21:43921 GetTrackedPrefHistogramCount(
922 user_prefs::tracked::kTrackedPrefHistogramReset,
923 BEGIN_ALLOW_SINGLE_BUCKET + 5));
[email protected]ae7bf342014-08-06 18:03:47924
925 EXPECT_EQ(protection_level_ < PROTECTION_ENABLED_EXTENSIONS,
926 extension_service()->GetExtensionById(kGoodCrxId, true) != NULL);
927
928 // Nothing else should have triggered.
[email protected]ae7bf342014-08-06 18:03:47929 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43930 0, GetTrackedPrefHistogramCount(
931 user_prefs::tracked::kTrackedPrefHistogramCleared, ALLOW_NONE));
932 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
933 user_prefs::tracked::kTrackedPrefHistogramInitialized,
934 ALLOW_NONE));
935 EXPECT_EQ(0,
936 GetTrackedPrefHistogramCount(
937 user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
938 ALLOW_NONE));
939 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
940 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
941 ALLOW_NONE));
942 EXPECT_EQ(
943 0, GetTrackedPrefHistogramCount(
944 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
945 ALLOW_NONE));
proberge269fd092016-10-04 22:13:41946
947 if (SupportsRegistryValidation()) {
948 // Expect that the registry validation caught the invalid MAC in split
949 // pref #5 (extensions).
950 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
951 GetTrackedPrefHistogramCount(
952 user_prefs::tracked::kTrackedPrefHistogramChanged,
953 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
954 BEGIN_ALLOW_SINGLE_BUCKET + 5));
955 }
[email protected]ae7bf342014-08-06 18:03:47956 }
957};
958
959PREF_HASH_BROWSER_TEST(PrefHashBrowserTestChangedSplitPref, ChangedSplitPref);
gabb004a562014-09-16 12:45:22960
961// Verifies that adding a value to unprotected preferences for a key which is
962// still using the default (i.e. has no value stored in protected preferences)
963// doesn't allow that value to slip in with no valid MAC (regression test for
964// http://crbug.com/414554)
965class PrefHashBrowserTestUntrustedAdditionToPrefs
966 : public PrefHashBrowserTestBase {
967 public:
dcheng8f4b8622014-10-23 16:37:48968 void SetupPreferences() override {
gabb004a562014-09-16 12:45:22969 // Ensure there is no user-selected value for kRestoreOnStartup.
970 EXPECT_FALSE(
971 profile()->GetPrefs()->GetUserPrefValue(prefs::kRestoreOnStartup));
972 }
973
dcheng8f4b8622014-10-23 16:37:48974 void AttackPreferencesOnDisk(
gabb004a562014-09-16 12:45:22975 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:17976 base::DictionaryValue* protected_preferences) override {
gabb004a562014-09-16 12:45:22977 unprotected_preferences->SetInteger(prefs::kRestoreOnStartup,
978 SessionStartupPref::LAST);
979 }
980
dcheng8f4b8622014-10-23 16:37:48981 void VerifyReactionToPrefAttack() override {
gabb004a562014-09-16 12:45:22982 // Expect a single Changed event for tracked pref #3 (kRestoreOnStartup) if
983 // not protecting; if protection is enabled the change should be a no-op.
984 int changed_expected =
985 protection_level_ == PROTECTION_DISABLED_FOR_GROUP ? 1 : 0;
deepak.m113481c82015-12-16 05:21:43986 EXPECT_EQ((protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
987 protection_level_ < PROTECTION_ENABLED_BASIC)
988 ? changed_expected
989 : 0,
gabb004a562014-09-16 12:45:22990 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:43991 user_prefs::tracked::kTrackedPrefHistogramChanged,
992 BEGIN_ALLOW_SINGLE_BUCKET + 3));
gabb004a562014-09-16 12:45:22993 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:43994 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
995 ? num_tracked_prefs() - changed_expected
996 : 0,
997 GetTrackedPrefHistogramCount(
998 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
999
1000 EXPECT_EQ((protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
1001 protection_level_ < PROTECTION_ENABLED_BASIC)
1002 ? 1
1003 : 0,
1004 GetTrackedPrefHistogramCount(
1005 user_prefs::tracked::kTrackedPrefHistogramWantedReset,
1006 BEGIN_ALLOW_SINGLE_BUCKET + 3));
gabb004a562014-09-16 12:45:221007 EXPECT_EQ(0,
deepak.m113481c82015-12-16 05:21:431008 GetTrackedPrefHistogramCount(
1009 user_prefs::tracked::kTrackedPrefHistogramReset, ALLOW_NONE));
gabb004a562014-09-16 12:45:221010
1011 // Nothing else should have triggered.
gabb004a562014-09-16 12:45:221012 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:431013 0, GetTrackedPrefHistogramCount(
1014 user_prefs::tracked::kTrackedPrefHistogramCleared, ALLOW_NONE));
1015 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
1016 user_prefs::tracked::kTrackedPrefHistogramInitialized,
1017 ALLOW_NONE));
1018 EXPECT_EQ(0,
1019 GetTrackedPrefHistogramCount(
1020 user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
1021 ALLOW_NONE));
1022 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
1023 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
1024 ALLOW_NONE));
1025 EXPECT_EQ(
1026 0, GetTrackedPrefHistogramCount(
1027 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
1028 ALLOW_NONE));
proberge269fd092016-10-04 22:13:411029
1030 if (SupportsRegistryValidation()) {
1031 EXPECT_EQ((protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
1032 protection_level_ < PROTECTION_ENABLED_BASIC)
1033 ? changed_expected
1034 : 0,
1035 GetTrackedPrefHistogramCount(
1036 user_prefs::tracked::kTrackedPrefHistogramChanged,
1037 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
1038 BEGIN_ALLOW_SINGLE_BUCKET + 3));
1039 }
gabb004a562014-09-16 12:45:221040 }
1041};
1042
1043PREF_HASH_BROWSER_TEST(PrefHashBrowserTestUntrustedAdditionToPrefs,
1044 UntrustedAdditionToPrefs);
erikwrightf4e02b72014-09-17 20:25:451045
1046// Verifies that adding a value to unprotected preferences while wiping a
1047// user-selected value from protected preferences doesn't allow that value to
1048// slip in with no valid MAC (regression test for http://crbug.com/414554).
1049class PrefHashBrowserTestUntrustedAdditionToPrefsAfterWipe
1050 : public PrefHashBrowserTestBase {
1051 public:
dcheng8f4b8622014-10-23 16:37:481052 void SetupPreferences() override {
erikwrightf4e02b72014-09-17 20:25:451053 profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com");
1054 }
1055
dcheng8f4b8622014-10-23 16:37:481056 void AttackPreferencesOnDisk(
erikwrightf4e02b72014-09-17 20:25:451057 base::DictionaryValue* unprotected_preferences,
mostynb2b52d1db2014-10-07 02:47:171058 base::DictionaryValue* protected_preferences) override {
erikwrightf4e02b72014-09-17 20:25:451059 // Set or change the value in Preferences to the attacker's choice.
1060 unprotected_preferences->SetString(prefs::kHomePage, "http://example.net");
1061 // Clear the value in Secure Preferences, if any.
1062 if (protected_preferences)
1063 protected_preferences->Remove(prefs::kHomePage, NULL);
1064 }
1065
dcheng8f4b8622014-10-23 16:37:481066 void VerifyReactionToPrefAttack() override {
erikwrightf4e02b72014-09-17 20:25:451067 // Expect a single Changed event for tracked pref #2 (kHomePage) if
1068 // not protecting; if protection is enabled the change should be a Cleared.
1069 int changed_expected =
1070 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM &&
1071 protection_level_ < PROTECTION_ENABLED_BASIC
1072 ? 1 : 0;
1073 int cleared_expected =
1074 protection_level_ >= PROTECTION_ENABLED_BASIC
1075 ? 1 : 0;
1076 EXPECT_EQ(changed_expected,
erikwrightf4e02b72014-09-17 20:25:451077 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:431078 user_prefs::tracked::kTrackedPrefHistogramChanged,
1079 BEGIN_ALLOW_SINGLE_BUCKET + 2));
1080 EXPECT_EQ(cleared_expected,
1081 GetTrackedPrefHistogramCount(
1082 user_prefs::tracked::kTrackedPrefHistogramCleared,
1083 BEGIN_ALLOW_SINGLE_BUCKET + 2));
erikwrightf4e02b72014-09-17 20:25:451084 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:431085 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
1086 ? num_tracked_prefs() - changed_expected - cleared_expected
1087 : 0,
1088 GetTrackedPrefHistogramCount(
1089 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
1090
1091 EXPECT_EQ(changed_expected,
1092 GetTrackedPrefHistogramCount(
1093 user_prefs::tracked::kTrackedPrefHistogramWantedReset,
1094 BEGIN_ALLOW_SINGLE_BUCKET + 2));
erikwrightf4e02b72014-09-17 20:25:451095 EXPECT_EQ(0,
deepak.m113481c82015-12-16 05:21:431096 GetTrackedPrefHistogramCount(
1097 user_prefs::tracked::kTrackedPrefHistogramReset, ALLOW_NONE));
erikwrightf4e02b72014-09-17 20:25:451098
1099 // Nothing else should have triggered.
deepak.m113481c82015-12-16 05:21:431100 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
1101 user_prefs::tracked::kTrackedPrefHistogramInitialized,
1102 ALLOW_NONE));
erikwrightf4e02b72014-09-17 20:25:451103 EXPECT_EQ(0,
1104 GetTrackedPrefHistogramCount(
deepak.m113481c82015-12-16 05:21:431105 user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized,
1106 ALLOW_NONE));
1107 EXPECT_EQ(0, GetTrackedPrefHistogramCount(
1108 user_prefs::tracked::kTrackedPrefHistogramNullInitialized,
1109 ALLOW_NONE));
erikwrightf4e02b72014-09-17 20:25:451110 EXPECT_EQ(
deepak.m113481c82015-12-16 05:21:431111 0, GetTrackedPrefHistogramCount(
1112 user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId,
1113 ALLOW_NONE));
proberge269fd092016-10-04 22:13:411114
1115 if (SupportsRegistryValidation()) {
1116 EXPECT_EQ(changed_expected,
1117 GetTrackedPrefHistogramCount(
1118 user_prefs::tracked::kTrackedPrefHistogramChanged,
1119 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
1120 BEGIN_ALLOW_SINGLE_BUCKET + 2));
1121 EXPECT_EQ(cleared_expected,
1122 GetTrackedPrefHistogramCount(
1123 user_prefs::tracked::kTrackedPrefHistogramCleared,
1124 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
1125 BEGIN_ALLOW_SINGLE_BUCKET + 2));
1126 }
erikwrightf4e02b72014-09-17 20:25:451127 }
1128};
1129
1130PREF_HASH_BROWSER_TEST(PrefHashBrowserTestUntrustedAdditionToPrefsAfterWipe,
1131 UntrustedAdditionToPrefsAfterWipe);
proberge269fd092016-10-04 22:13:411132
1133#if defined(OS_WIN)
1134class PrefHashBrowserTestRegistryValidationFailure
1135 : public PrefHashBrowserTestBase {
1136 public:
1137 void SetupPreferences() override {
1138 profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com");
1139 }
1140
1141 void AttackPreferencesOnDisk(
1142 base::DictionaryValue* unprotected_preferences,
1143 base::DictionaryValue* protected_preferences) override {
1144 base::string16 registry_key =
1145 GetRegistryPathForTestProfile() + L"\\PreferenceMACs\\Default";
1146 base::win::RegKey key;
1147 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, registry_key.c_str(),
1148 KEY_SET_VALUE | KEY_WOW64_32KEY));
1149 // An incorrect hash should still have the correct size.
1150 ASSERT_EQ(ERROR_SUCCESS,
1151 key.WriteValue(L"homepage", base::string16(64, 'A').c_str()));
1152 }
1153
1154 void VerifyReactionToPrefAttack() override {
1155 EXPECT_EQ(
1156 protection_level_ > PROTECTION_DISABLED_ON_PLATFORM
1157 ? num_tracked_prefs()
1158 : 0,
1159 GetTrackedPrefHistogramCount(
1160 user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY));
1161
1162 if (SupportsRegistryValidation()) {
1163 // Expect that the registry validation caught the invalid MAC for pref #2
1164 // (homepage).
1165 EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0,
1166 GetTrackedPrefHistogramCount(
1167 user_prefs::tracked::kTrackedPrefHistogramChanged,
1168 user_prefs::tracked::kTrackedPrefRegistryValidationSuffix,
1169 BEGIN_ALLOW_SINGLE_BUCKET + 2));
1170 }
1171 }
1172};
1173
1174PREF_HASH_BROWSER_TEST(PrefHashBrowserTestRegistryValidationFailure,
1175 RegistryValidationFailure);
1176#endif
a-v-y38416862016-12-08 08:40:131177
1178// Verifies that all preferences related to choice of default search engine are
1179// protected.
1180class PrefHashBrowserTestDefaultSearch : public PrefHashBrowserTestBase {
1181 public:
1182 void SetupPreferences() override {
1183 // Set user selected default search engine.
1184 DefaultSearchManager default_search_manager(
1185 profile()->GetPrefs(), DefaultSearchManager::ObserverCallback());
1186 DefaultSearchManager::Source dse_source =
1187 static_cast<DefaultSearchManager::Source>(-1);
1188
1189 TemplateURLData user_dse;
1190 user_dse.SetKeyword(base::UTF8ToUTF16("userkeyword"));
1191 user_dse.SetShortName(base::UTF8ToUTF16("username"));
1192 user_dse.SetURL("http://user_default_engine/search?q=good_user_query");
1193 default_search_manager.SetUserSelectedDefaultSearchEngine(user_dse);
1194
1195 const TemplateURLData* current_dse =
1196 default_search_manager.GetDefaultSearchEngine(&dse_source);
1197 EXPECT_EQ(DefaultSearchManager::FROM_USER, dse_source);
1198 EXPECT_EQ(current_dse->keyword(), base::UTF8ToUTF16("userkeyword"));
1199 EXPECT_EQ(current_dse->short_name(), base::UTF8ToUTF16("username"));
1200 EXPECT_EQ(current_dse->url(),
1201 "http://user_default_engine/search?q=good_user_query");
1202 }
1203
1204 void AttackPreferencesOnDisk(
1205 base::DictionaryValue* unprotected_preferences,
1206 base::DictionaryValue* protected_preferences) override {
1207 static constexpr char default_search_provider_data[] = R"(
1208 {
1209 "default_search_provider_data" : {
1210 "template_url_data" : {
1211 "keyword" : "badkeyword",
1212 "short_name" : "badname",
1213 "url" : "http://bad_default_engine/search?q=dirty_user_query"
1214 }
1215 }
1216 })";
1217 static constexpr char search_provider_overrides[] = R"(
1218 {
1219 "search_provider_overrides" : [
1220 {
1221 "keyword" : "badkeyword",
1222 "name" : "badname",
1223 "search_url" : "http://bad_default_engine/search?q=dirty_user_query",
1224 "encoding" : "utf-8",
1225 "id" : 1
1226 }, {
1227 "keyword" : "badkeyword2",
1228 "name" : "badname2",
1229 "search_url" : "http://bad_default_engine2/search?q=dirty_user_query",
1230 "encoding" : "utf-8",
1231 "id" : 2
1232 }
1233 ]
1234 })";
a-v-y38416862016-12-08 08:40:131235
1236 // Try to override default search in all three of available preferences.
1237 auto attack1 = base::DictionaryValue::From(
1238 base::JSONReader::Read(default_search_provider_data));
1239 auto attack2 = base::DictionaryValue::From(
1240 base::JSONReader::Read(search_provider_overrides));
a-v-y38416862016-12-08 08:40:131241 unprotected_preferences->MergeDictionary(attack1.get());
1242 unprotected_preferences->MergeDictionary(attack2.get());
a-v-y38416862016-12-08 08:40:131243 if (protected_preferences) {
1244 // Override here, too.
1245 protected_preferences->MergeDictionary(attack1.get());
1246 protected_preferences->MergeDictionary(attack2.get());
a-v-y38416862016-12-08 08:40:131247 }
1248 }
1249
1250 void VerifyReactionToPrefAttack() override {
1251 DefaultSearchManager default_search_manager(
1252 profile()->GetPrefs(), DefaultSearchManager::ObserverCallback());
1253 DefaultSearchManager::Source dse_source =
1254 static_cast<DefaultSearchManager::Source>(-1);
1255
1256 const TemplateURLData* current_dse =
1257 default_search_manager.GetDefaultSearchEngine(&dse_source);
1258
1259 if (protection_level_ < PROTECTION_ENABLED_DSE) {
1260// This doesn't work on OS_CHROMEOS because we fail to attack Preferences.
1261#if !defined(OS_CHROMEOS)
1262 // Attack is successful.
1263 EXPECT_EQ(DefaultSearchManager::FROM_USER, dse_source);
1264 EXPECT_EQ(current_dse->keyword(), base::UTF8ToUTF16("badkeyword"));
1265 EXPECT_EQ(current_dse->short_name(), base::UTF8ToUTF16("badname"));
1266 EXPECT_EQ(current_dse->url(),
1267 "http://bad_default_engine/search?q=dirty_user_query");
1268#endif
1269 } else {
1270 // Attack fails.
1271 EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, dse_source);
1272 EXPECT_NE(current_dse->keyword(), base::UTF8ToUTF16("badkeyword"));
1273 EXPECT_NE(current_dse->short_name(), base::UTF8ToUTF16("badname"));
1274 EXPECT_NE(current_dse->url(),
1275 "http://bad_default_engine/search?q=dirty_user_query");
1276 }
1277 }
1278};
1279
1280PREF_HASH_BROWSER_TEST(PrefHashBrowserTestDefaultSearch, SearchProtected);