blacklist_test.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2013 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 5#include "base/environment.h" 6#include "base/files/file_path.h" 7#include "base/files/scoped_temp_dir.h" 8#include "base/i18n/case_conversion.h" 9#include "base/path_service.h" 10#include "base/scoped_native_library.h" 11#include "base/strings/string16.h" 12#include "base/strings/string_number_conversions.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/test/test_reg_util_win.h" 15#include "base/win/registry.h" 16#include "chrome_elf/blacklist/blacklist.h" 17#include "chrome_elf/blacklist/test/blacklist_test_main_dll.h" 18#include "chrome_elf/chrome_elf_constants.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "version.h" // NOLINT 21 22const wchar_t kTestDllName1[] = L"blacklist_test_dll_1.dll"; 23const wchar_t kTestDllName2[] = L"blacklist_test_dll_2.dll"; 24const wchar_t kTestDllName3[] = L"blacklist_test_dll_3.dll"; 25 26const wchar_t kDll2Beacon[] = L"{F70A0100-2889-4629-9B44-610FE5C73231}"; 27const wchar_t kDll3Beacon[] = L"{9E056AEC-169E-400c-B2D0-5A07E3ACE2EB}"; 28 29extern const wchar_t* kEnvVars[]; 30 31extern "C" { 32// When modifying the blacklist in the test process, use the exported test dll 33// functions on the test blacklist dll, not the ones linked into the test 34// executable itself. 35__declspec(dllimport) void TestDll_AddDllsFromRegistryToBlacklist(); 36__declspec(dllimport) bool TestDll_AddDllToBlacklist(const wchar_t* dll_name); 37__declspec(dllimport) bool TestDll_IsBlacklistInitialized(); 38__declspec(dllimport) bool TestDll_RemoveDllFromBlacklist( 39 const wchar_t* dll_name); 40__declspec(dllimport) bool TestDll_SuccessfullyBlocked( 41 const wchar_t** blocked_dlls, 42 int* size); 43} 44 45namespace { 46 47class BlacklistTest : public testing::Test { 48 protected: 49 BlacklistTest() : override_manager_() { 50 override_manager_.OverrideRegistry(HKEY_CURRENT_USER, L"beacon_test"); 51 } 52 53 scoped_ptr<base::win::RegKey> blacklist_registry_key_; 54 registry_util::RegistryOverrideManager override_manager_; 55 56 private: 57 virtual void SetUp() { 58 // Force an import from blacklist_test_main_dll. 59 InitBlacklistTestDll(); 60 blacklist_registry_key_.reset( 61 new base::win::RegKey(HKEY_CURRENT_USER, 62 blacklist::kRegistryBeaconPath, 63 KEY_QUERY_VALUE | KEY_SET_VALUE)); 64 } 65 66 virtual void TearDown() { 67 TestDll_RemoveDllFromBlacklist(kTestDllName1); 68 TestDll_RemoveDllFromBlacklist(kTestDllName2); 69 TestDll_RemoveDllFromBlacklist(kTestDllName3); 70 } 71}; 72 73struct TestData { 74 const wchar_t* dll_name; 75 const wchar_t* dll_beacon; 76} test_data[] = {{kTestDllName2, kDll2Beacon}, {kTestDllName3, kDll3Beacon}}; 77 78TEST_F(BlacklistTest, Beacon) { 79 // Ensure that the beacon state starts off 'running' for this version. 80 LONG result = blacklist_registry_key_->WriteValue( 81 blacklist::kBeaconState, blacklist::BLACKLIST_SETUP_RUNNING); 82 EXPECT_EQ(ERROR_SUCCESS, result); 83 84 result = blacklist_registry_key_->WriteValue(blacklist::kBeaconVersion, 85 TEXT(CHROME_VERSION_STRING)); 86 EXPECT_EQ(ERROR_SUCCESS, result); 87 88 // First call should find the beacon and reset it. 89 EXPECT_TRUE(blacklist::ResetBeacon()); 90 91 // First call should succeed as the beacon is enabled. 92 EXPECT_TRUE(blacklist::LeaveSetupBeacon()); 93} 94 95TEST_F(BlacklistTest, AddAndRemoveModules) { 96 EXPECT_TRUE(blacklist::AddDllToBlacklist(L"foo.dll")); 97 // Adding the same item twice should be idempotent. 98 EXPECT_TRUE(blacklist::AddDllToBlacklist(L"foo.dll")); 99 EXPECT_TRUE(blacklist::RemoveDllFromBlacklist(L"foo.dll")); 100 EXPECT_FALSE(blacklist::RemoveDllFromBlacklist(L"foo.dll")); 101 102 // Increase the blacklist size by 1 to include the NULL pointer 103 // that marks the end. 104 int empty_spaces = blacklist::kTroublesomeDllsMaxCount - ( 105 blacklist::BlacklistSize() + 1); 106 std::vector<base::string16> added_dlls; 107 added_dlls.reserve(empty_spaces); 108 for (int i = 0; i < empty_spaces; ++i) { 109 added_dlls.push_back(base::IntToString16(i) + L".dll"); 110 EXPECT_TRUE(blacklist::AddDllToBlacklist(added_dlls[i].c_str())) << i; 111 } 112 EXPECT_FALSE(blacklist::AddDllToBlacklist(L"overflow.dll")); 113 for (int i = 0; i < empty_spaces; ++i) { 114 EXPECT_TRUE(blacklist::RemoveDllFromBlacklist(added_dlls[i].c_str())) << i; 115 } 116 EXPECT_FALSE(blacklist::RemoveDllFromBlacklist(added_dlls[0].c_str())); 117 EXPECT_FALSE(blacklist::RemoveDllFromBlacklist( 118 added_dlls[empty_spaces - 1].c_str())); 119} 120 121TEST_F(BlacklistTest, SuccessfullyBlocked) { 122 // Ensure that we have at least 5 dlls to blacklist. 123 int blacklist_size = blacklist::BlacklistSize(); 124 const int kDesiredBlacklistSize = 5; 125 for (int i = blacklist_size; i < kDesiredBlacklistSize; ++i) { 126 base::string16 new_dll_name(base::IntToString16(i) + L".dll"); 127 EXPECT_TRUE(blacklist::AddDllToBlacklist(new_dll_name.c_str())); 128 } 129 130 // Block 5 dlls, one at a time, starting from the end of the list, and 131 // ensuring SuccesfullyBlocked correctly passes the list of blocked dlls. 132 for (int i = 0; i < kDesiredBlacklistSize; ++i) { 133 blacklist::BlockedDll(i); 134 135 int size = 0; 136 blacklist::SuccessfullyBlocked(NULL, &size); 137 EXPECT_EQ(i + 1, size); 138 139 std::vector<const wchar_t*> blocked_dlls(size); 140 blacklist::SuccessfullyBlocked(&(blocked_dlls[0]), &size); 141 EXPECT_EQ(i + 1, size); 142 143 for (size_t j = 0; j < blocked_dlls.size(); ++j) { 144 EXPECT_EQ(blocked_dlls[j], blacklist::g_troublesome_dlls[j]); 145 } 146 } 147} 148 149void CheckBlacklistedDllsNotLoaded() { 150 base::FilePath current_dir; 151 ASSERT_TRUE(PathService::Get(base::DIR_EXE, ¤t_dir)); 152 153 for (int i = 0; i < arraysize(test_data); ++i) { 154 // Ensure that the dll has not been loaded both by inspecting the handle 155 // returned by LoadLibrary and by looking for an environment variable that 156 // is set when the DLL's entry point is called. 157 base::ScopedNativeLibrary dll_blacklisted( 158 current_dir.Append(test_data[i].dll_name)); 159 EXPECT_FALSE(dll_blacklisted.is_valid()); 160 EXPECT_EQ(0u, ::GetEnvironmentVariable(test_data[i].dll_beacon, NULL, 0)); 161 dll_blacklisted.Reset(NULL); 162 163 // Ensure that the dll is recorded as blocked. 164 int array_size = 1; 165 const wchar_t* blocked_dll = NULL; 166 TestDll_SuccessfullyBlocked(&blocked_dll, &array_size); 167 EXPECT_EQ(1, array_size); 168 EXPECT_EQ(test_data[i].dll_name, base::string16(blocked_dll)); 169 170 // Remove the DLL from the blacklist. Ensure that it loads and that its 171 // entry point was called. 172 EXPECT_TRUE(TestDll_RemoveDllFromBlacklist(test_data[i].dll_name)); 173 base::ScopedNativeLibrary dll(current_dir.Append(test_data[i].dll_name)); 174 EXPECT_TRUE(dll.is_valid()); 175 EXPECT_NE(0u, ::GetEnvironmentVariable(test_data[i].dll_beacon, NULL, 0)); 176 dll.Reset(NULL); 177 178 ::SetEnvironmentVariable(test_data[i].dll_beacon, NULL); 179 180 // Ensure that the dll won't load even if the name has different 181 // capitalization. 182 base::string16 uppercase_name = base::i18n::ToUpper(test_data[i].dll_name); 183 EXPECT_TRUE(TestDll_AddDllToBlacklist(uppercase_name.c_str())); 184 base::ScopedNativeLibrary dll_blacklisted_different_case( 185 current_dir.Append(test_data[i].dll_name)); 186 EXPECT_FALSE(dll_blacklisted_different_case.is_valid()); 187 EXPECT_EQ(0u, ::GetEnvironmentVariable(test_data[i].dll_beacon, NULL, 0)); 188 dll_blacklisted_different_case.Reset(NULL); 189 190 EXPECT_TRUE(TestDll_RemoveDllFromBlacklist(uppercase_name.c_str())); 191 192 // The blocked dll was removed, so we shouldn't get anything returned 193 // here. 194 int num_blocked_dlls = 0; 195 TestDll_SuccessfullyBlocked(NULL, &num_blocked_dlls); 196 EXPECT_EQ(0, num_blocked_dlls); 197 } 198} 199 200TEST_F(BlacklistTest, LoadBlacklistedLibrary) { 201 base::FilePath current_dir; 202 ASSERT_TRUE(PathService::Get(base::DIR_EXE, ¤t_dir)); 203 204 // Ensure that the blacklist is loaded. 205 ASSERT_TRUE(TestDll_IsBlacklistInitialized()); 206 207 // Test that an un-blacklisted DLL can load correctly. 208 base::ScopedNativeLibrary dll1(current_dir.Append(kTestDllName1)); 209 EXPECT_TRUE(dll1.is_valid()); 210 dll1.Reset(NULL); 211 212 int num_blocked_dlls = 0; 213 TestDll_SuccessfullyBlocked(NULL, &num_blocked_dlls); 214 EXPECT_EQ(0, num_blocked_dlls); 215 216 // Add all DLLs to the blacklist then check they are blocked. 217 for (int i = 0; i < arraysize(test_data); ++i) { 218 EXPECT_TRUE(TestDll_AddDllToBlacklist(test_data[i].dll_name)); 219 } 220 CheckBlacklistedDllsNotLoaded(); 221} 222 223TEST_F(BlacklistTest, AddDllsFromRegistryToBlacklist) { 224 // Ensure that the blacklist is loaded. 225 ASSERT_TRUE(TestDll_IsBlacklistInitialized()); 226 227 // Delete the finch registry key to clear its values. 228 base::win::RegKey key(HKEY_CURRENT_USER, 229 blacklist::kRegistryFinchListPath, 230 KEY_QUERY_VALUE | KEY_SET_VALUE); 231 key.DeleteKey(L""); 232 233 // Add the test dlls to the registry (with their name as both key and value). 234 base::win::RegKey finch_blacklist_registry_key( 235 HKEY_CURRENT_USER, 236 blacklist::kRegistryFinchListPath, 237 KEY_QUERY_VALUE | KEY_SET_VALUE); 238 for (int i = 0; i < arraysize(test_data); ++i) { 239 finch_blacklist_registry_key.WriteValue(test_data[i].dll_name, 240 test_data[i].dll_name); 241 } 242 243 TestDll_AddDllsFromRegistryToBlacklist(); 244 CheckBlacklistedDllsNotLoaded(); 245} 246 247void TestResetBeacon(scoped_ptr<base::win::RegKey>& key, 248 DWORD input_state, 249 DWORD expected_output_state) { 250 LONG result = key->WriteValue(blacklist::kBeaconState, input_state); 251 EXPECT_EQ(ERROR_SUCCESS, result); 252 253 EXPECT_TRUE(blacklist::ResetBeacon()); 254 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX; 255 result = key->ReadValueDW(blacklist::kBeaconState, &blacklist_state); 256 EXPECT_EQ(ERROR_SUCCESS, result); 257 EXPECT_EQ(expected_output_state, blacklist_state); 258} 259 260TEST_F(BlacklistTest, ResetBeacon) { 261 // Ensure that ResetBeacon resets properly on successful runs and not on 262 // failed or disabled runs. 263 TestResetBeacon(blacklist_registry_key_, 264 blacklist::BLACKLIST_SETUP_RUNNING, 265 blacklist::BLACKLIST_ENABLED); 266 267 TestResetBeacon(blacklist_registry_key_, 268 blacklist::BLACKLIST_SETUP_FAILED, 269 blacklist::BLACKLIST_SETUP_FAILED); 270 271 TestResetBeacon(blacklist_registry_key_, 272 blacklist::BLACKLIST_DISABLED, 273 blacklist::BLACKLIST_DISABLED); 274} 275 276TEST_F(BlacklistTest, SetupFailed) { 277 // Ensure that when the number of failed tries reaches the maximum allowed, 278 // the blacklist state is set to failed. 279 LONG result = blacklist_registry_key_->WriteValue( 280 blacklist::kBeaconState, blacklist::BLACKLIST_SETUP_RUNNING); 281 EXPECT_EQ(ERROR_SUCCESS, result); 282 283 // Set the attempt count so that on the next failure the blacklist is 284 // disabled. 285 result = blacklist_registry_key_->WriteValue( 286 blacklist::kBeaconAttemptCount, blacklist::kBeaconMaxAttempts - 1); 287 EXPECT_EQ(ERROR_SUCCESS, result); 288 289 EXPECT_FALSE(blacklist::LeaveSetupBeacon()); 290 291 DWORD attempt_count = 0; 292 blacklist_registry_key_->ReadValueDW(blacklist::kBeaconAttemptCount, 293 &attempt_count); 294 EXPECT_EQ(attempt_count, blacklist::kBeaconMaxAttempts); 295 296 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX; 297 result = blacklist_registry_key_->ReadValueDW(blacklist::kBeaconState, 298 &blacklist_state); 299 EXPECT_EQ(ERROR_SUCCESS, result); 300 EXPECT_EQ(blacklist_state, blacklist::BLACKLIST_SETUP_FAILED); 301} 302 303TEST_F(BlacklistTest, SetupSucceeded) { 304 // Starting with the enabled beacon should result in the setup running state 305 // and the attempt counter reset to zero. 306 LONG result = blacklist_registry_key_->WriteValue( 307 blacklist::kBeaconState, blacklist::BLACKLIST_ENABLED); 308 EXPECT_EQ(ERROR_SUCCESS, result); 309 result = blacklist_registry_key_->WriteValue(blacklist::kBeaconAttemptCount, 310 blacklist::kBeaconMaxAttempts); 311 EXPECT_EQ(ERROR_SUCCESS, result); 312 313 EXPECT_TRUE(blacklist::LeaveSetupBeacon()); 314 315 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX; 316 blacklist_registry_key_->ReadValueDW(blacklist::kBeaconState, 317 &blacklist_state); 318 EXPECT_EQ(blacklist_state, blacklist::BLACKLIST_SETUP_RUNNING); 319 320 DWORD attempt_count = blacklist::kBeaconMaxAttempts; 321 blacklist_registry_key_->ReadValueDW(blacklist::kBeaconAttemptCount, 322 &attempt_count); 323 EXPECT_EQ(static_cast<DWORD>(0), attempt_count); 324} 325 326} // namespace 327