Index: chrome/browser/prefs/tracked/pref_hash_browsertest.cc |
diff --git a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc |
index 7703e89b68c07dd46165d956894f66885c52b3b6..f77616a6b84ab5faa574b096939d1e39677681e3 100644 |
--- a/chrome/browser/prefs/tracked/pref_hash_browsertest.cc |
+++ b/chrome/browser/prefs/tracked/pref_hash_browsertest.cc |
@@ -38,6 +38,10 @@ |
#include "chromeos/chromeos_switches.h" |
#endif |
+#if defined(OS_WIN) |
+#include "base/test/test_reg_util_win.h" |
+#endif |
+ |
namespace { |
// Extension ID of chrome/test/data/extensions/good.crx |
@@ -56,14 +60,27 @@ enum AllowedBuckets { |
ALLOW_ANY |
}; |
+#if defined(OS_WIN) |
+base::string16 GetRegistryPathForTestProfile() { |
+ base::FilePath profile_dir; |
+ EXPECT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &profile_dir)); |
+ return L"SOFTWARE\\Chromium\\PrefHashBrowserTest\\" + |
+ profile_dir.BaseName().value(); |
+} |
+#endif |
+ |
// Returns the number of times |histogram_name| was reported so far; adding the |
// results of the first 100 buckets (there are only ~19 reporting IDs as of this |
// writing; varies depending on the platform). |allowed_buckets| hints at extra |
// requirements verified in this method (see AllowedBuckets for details). |
int GetTrackedPrefHistogramCount(const char* histogram_name, |
+ const char* histogram_suffix, |
int allowed_buckets) { |
+ std::string full_histogram_name(histogram_name); |
+ if (*histogram_suffix) |
+ full_histogram_name.append(".").append(histogram_suffix); |
const base::HistogramBase* histogram = |
- base::StatisticsRecorder::FindHistogram(histogram_name); |
+ base::StatisticsRecorder::FindHistogram(full_histogram_name); |
if (!histogram) |
return 0; |
@@ -82,6 +99,13 @@ int GetTrackedPrefHistogramCount(const char* histogram_name, |
return sum; |
} |
+// Helper function to call GetTrackedPrefHistogramCount with no external |
+// validation suffix. |
+int GetTrackedPrefHistogramCount(const char* histogram_name, |
+ int allowed_buckets) { |
+ return GetTrackedPrefHistogramCount(histogram_name, "", allowed_buckets); |
+} |
+ |
std::unique_ptr<base::DictionaryValue> ReadPrefsDictionary( |
const base::FilePath& pref_file) { |
JSONFileValueDeserializer deserializer(pref_file); |
@@ -101,6 +125,16 @@ std::unique_ptr<base::DictionaryValue> ReadPrefsDictionary( |
static_cast<base::DictionaryValue*>(prefs.release())); |
} |
+// Returns whether external validation is supported on the platform through |
+// storing MACs in the registry. |
+bool SupportsRegistryValidation() { |
+#if defined(OS_WIN) |
+ return true; |
+#else |
+ return false; |
+#endif |
+} |
+ |
#define PREF_HASH_BROWSER_TEST(fixture, test_name) \ |
IN_PROC_BROWSER_TEST_P(fixture, PRE_##test_name) { \ |
SetupPreferences(); \ |
@@ -233,6 +267,44 @@ class PrefHashBrowserTestBase |
// Bots are on a domain, turn off the domain check for settings hardening in |
// order to be able to test all SettingsEnforcement groups. |
chrome_prefs::DisableDomainCheckForTesting(); |
+ |
+#if defined(OS_WIN) |
+ // Avoid polluting prefs for the user and the bots by writing to a specific |
+ // testing registry path. |
+ registry_key_for_external_validation_ = GetRegistryPathForTestProfile(); |
+ ProfilePrefStoreManager::SetPreferenceValidationRegistryPathForTesting( |
+ ®istry_key_for_external_validation_); |
+ |
+ // Keys should be unique, but to avoid flakes in the long run make sure an |
+ // identical test key wasn't left behind by a previous test. |
+ if (IsPRETest()) { |
+ base::win::RegKey key; |
+ if (key.Open(HKEY_CURRENT_USER, |
+ registry_key_for_external_validation_.c_str(), |
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { |
+ LONG result = key.DeleteKey(L""); |
+ ASSERT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); |
+ } |
+ } |
+#endif |
+ } |
+ |
+ void TearDown() override { |
+#if defined(OS_WIN) |
+ // When done, delete the Registry key to avoid polluting the registry. |
+ // TODO(proberge): it would be nice to delete keys from interrupted tests |
+ // as well. |
+ if (!IsPRETest()) { |
+ base::string16 registry_key = GetRegistryPathForTestProfile(); |
+ base::win::RegKey key; |
+ if (key.Open(HKEY_CURRENT_USER, registry_key.c_str(), |
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { |
+ LONG result = key.DeleteKey(L""); |
+ ASSERT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); |
+ } |
+ } |
+#endif |
+ ExtensionBrowserTest::TearDown(); |
} |
// In the PRE_ test, find the number of tracked preferences that were |
@@ -266,6 +338,23 @@ class PrefHashBrowserTestBase |
EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0, |
num_split_tracked_prefs); |
+ if (SupportsRegistryValidation()) { |
+ // Same checks as above, but for the registry. |
+ num_tracked_prefs_ = GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramNullInitialized, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ ALLOW_ANY); |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM, |
+ num_tracked_prefs_ > 0); |
+ |
+ int num_split_tracked_prefs = GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramUnchanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 5); |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0, |
+ num_split_tracked_prefs); |
+ } |
+ |
num_tracked_prefs_ += num_split_tracked_prefs; |
std::string num_tracked_prefs_str = base::IntToString(num_tracked_prefs_); |
@@ -353,6 +442,10 @@ class PrefHashBrowserTestBase |
} |
int num_tracked_prefs_; |
+ |
+#if defined(OS_WIN) |
+ base::string16 registry_key_for_external_validation_; |
+#endif |
}; |
} // namespace |
@@ -407,6 +500,17 @@ class PrefHashBrowserTestUnchangedDefault : public PrefHashBrowserTestBase { |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ // Expect all prefs to be reported as Unchanged. |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM |
+ ? num_tracked_prefs() |
+ : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramUnchanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ ALLOW_ANY)); |
+ } |
} |
}; |
@@ -497,6 +601,15 @@ class PrefHashBrowserTestClearedAtomic : public PrefHashBrowserTestBase { |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ // Expect homepage clearance to have been noticed by registry validation. |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramCleared, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 2)); |
+ } |
} |
}; |
@@ -619,6 +732,18 @@ class PrefHashBrowserTestUntrustedInitialized : public PrefHashBrowserTestBase { |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ // The MACs have been cleared but the preferences have not been tampered. |
+ // The registry should report all prefs as unchanged. |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM |
+ ? num_tracked_prefs() |
+ : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramUnchanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ ALLOW_ANY)); |
+ } |
} |
}; |
@@ -709,6 +834,15 @@ class PrefHashBrowserTestChangedAtomic : public PrefHashBrowserTestBase { |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ // Expect a single Changed event for tracked pref #4 (startup URLs). |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramChanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 4)); |
+ } |
} |
}; |
@@ -806,6 +940,16 @@ class PrefHashBrowserTestChangedSplitPref : public PrefHashBrowserTestBase { |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ // Expect that the registry validation caught the invalid MAC in split |
+ // pref #5 (extensions). |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramChanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 5)); |
+ } |
} |
}; |
@@ -879,6 +1023,17 @@ class PrefHashBrowserTestUntrustedAdditionToPrefs |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ EXPECT_EQ((protection_level_ > PROTECTION_DISABLED_ON_PLATFORM && |
+ protection_level_ < PROTECTION_ENABLED_BASIC) |
+ ? changed_expected |
+ : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramChanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 3)); |
+ } |
} |
}; |
@@ -953,8 +1108,66 @@ class PrefHashBrowserTestUntrustedAdditionToPrefsAfterWipe |
0, GetTrackedPrefHistogramCount( |
user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId, |
ALLOW_NONE)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ EXPECT_EQ(changed_expected, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramChanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 2)); |
+ EXPECT_EQ(cleared_expected, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramCleared, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 2)); |
+ } |
} |
}; |
PREF_HASH_BROWSER_TEST(PrefHashBrowserTestUntrustedAdditionToPrefsAfterWipe, |
UntrustedAdditionToPrefsAfterWipe); |
+ |
+#if defined(OS_WIN) |
+class PrefHashBrowserTestRegistryValidationFailure |
+ : public PrefHashBrowserTestBase { |
+ public: |
+ void SetupPreferences() override { |
+ profile()->GetPrefs()->SetString(prefs::kHomePage, "http://example.com"); |
+ } |
+ |
+ void AttackPreferencesOnDisk( |
+ base::DictionaryValue* unprotected_preferences, |
+ base::DictionaryValue* protected_preferences) override { |
+ base::string16 registry_key = |
+ GetRegistryPathForTestProfile() + L"\\PreferenceMACs\\Default"; |
+ base::win::RegKey key; |
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, registry_key.c_str(), |
+ KEY_SET_VALUE | KEY_WOW64_32KEY)); |
+ // An incorrect hash should still have the correct size. |
+ ASSERT_EQ(ERROR_SUCCESS, |
+ key.WriteValue(L"homepage", base::string16(64, 'A').c_str())); |
+ } |
+ |
+ void VerifyReactionToPrefAttack() override { |
+ EXPECT_EQ( |
+ protection_level_ > PROTECTION_DISABLED_ON_PLATFORM |
+ ? num_tracked_prefs() |
+ : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramUnchanged, ALLOW_ANY)); |
+ |
+ if (SupportsRegistryValidation()) { |
+ // Expect that the registry validation caught the invalid MAC for pref #2 |
+ // (homepage). |
+ EXPECT_EQ(protection_level_ > PROTECTION_DISABLED_ON_PLATFORM ? 1 : 0, |
+ GetTrackedPrefHistogramCount( |
+ user_prefs::tracked::kTrackedPrefHistogramChanged, |
+ user_prefs::tracked::kTrackedPrefRegistryValidationSuffix, |
+ BEGIN_ALLOW_SINGLE_BUCKET + 2)); |
+ } |
+ } |
+}; |
+ |
+PREF_HASH_BROWSER_TEST(PrefHashBrowserTestRegistryValidationFailure, |
+ RegistryValidationFailure); |
+#endif |