chrome_elf_init_win.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1// 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 5#include "base/bind.h" 6#include "base/metrics/field_trial.h" 7#include "base/metrics/histogram.h" 8#include "base/metrics/sparse_histogram.h" 9#include "base/strings/utf_string_conversions.h" 10#include "base/win/registry.h" 11#include "chrome/browser/chrome_elf_init_win.h" 12#include "chrome_elf/blacklist/blacklist.h" 13#include "chrome_elf/chrome_elf_constants.h" 14#include "chrome_elf/dll_hash/dll_hash.h" 15#include "components/variations/variations_associated_data.h" 16#include "content/public/browser/browser_thread.h" 17#include "version.h" // NOLINT 18 19const char kBrowserBlacklistTrialName[] = "BrowserBlacklist"; 20const char kBrowserBlacklistTrialDisabledGroupName[] = "NoBlacklist"; 21 22namespace { 23 24// How long to wait, in seconds, before reporting for the second (and last 25// time), what dlls were blocked from the browser process. 26const int kBlacklistReportingDelaySec = 600; 27 28// This enum is used to define the buckets for an enumerated UMA histogram. 29// Hence, 30// (a) existing enumerated constants should never be deleted or reordered, and 31// (b) new constants should only be appended in front of 32// BLACKLIST_SETUP_EVENT_MAX. 33enum BlacklistSetupEventType { 34 // The blacklist beacon has placed to enable the browser blacklisting. 35 BLACKLIST_SETUP_ENABLED = 0, 36 37 // The blacklist was successfully enabled. 38 BLACKLIST_SETUP_RAN_SUCCESSFULLY, 39 40 // The blacklist setup code failed to execute. 41 BLACKLIST_SETUP_FAILED, 42 43 // The blacklist thunk setup code failed. This is probably an indication 44 // that something else patched that code first. 45 BLACKLIST_THUNK_SETUP_FAILED, 46 47 // Deprecated. The blacklist interception code failed to execute. 48 BLACKLIST_INTERCEPTION_FAILED, 49 50 // The blacklist was disabled for this run (after it failed too many times). 51 BLACKLIST_SETUP_DISABLED, 52 53 // Always keep this at the end. 54 BLACKLIST_SETUP_EVENT_MAX, 55}; 56 57void RecordBlacklistSetupEvent(BlacklistSetupEventType blacklist_setup_event) { 58 UMA_HISTOGRAM_ENUMERATION("Blacklist.Setup", 59 blacklist_setup_event, 60 BLACKLIST_SETUP_EVENT_MAX); 61} 62 63// Report which DLLs were prevented from being loaded. 64void ReportSuccessfulBlocks() { 65 // Figure out how many dlls were blocked. 66 int num_blocked_dlls = 0; 67 blacklist::SuccessfullyBlocked(NULL, &num_blocked_dlls); 68 69 if (num_blocked_dlls == 0) 70 return; 71 72 // Now retrieve the list of blocked dlls. 73 std::vector<const wchar_t*> blocked_dlls(num_blocked_dlls); 74 blacklist::SuccessfullyBlocked(&blocked_dlls[0], &num_blocked_dlls); 75 76 // Send up the hashes of the blocked dlls via UMA. 77 for (size_t i = 0; i < blocked_dlls.size(); ++i) { 78 std::string dll_name_utf8; 79 base::WideToUTF8(blocked_dlls[i], wcslen(blocked_dlls[i]), &dll_name_utf8); 80 int uma_hash = DllNameToHash(dll_name_utf8); 81 82 UMA_HISTOGRAM_SPARSE_SLOWLY("Blacklist.Blocked", uma_hash); 83 } 84} 85 86} // namespace 87 88void InitializeChromeElf() { 89 if (base::FieldTrialList::FindFullName(kBrowserBlacklistTrialName) == 90 kBrowserBlacklistTrialDisabledGroupName) { 91 // Disable the blacklist for all future runs by removing the beacon. 92 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER); 93 blacklist_registry_key.DeleteKey(blacklist::kRegistryBeaconPath); 94 } else { 95 AddFinchBlacklistToRegistry(); 96 BrowserBlacklistBeaconSetup(); 97 } 98 99 // Report all successful blacklist interceptions. 100 ReportSuccessfulBlocks(); 101 102 // Schedule another task to report all sucessful interceptions later. 103 // This time delay should be long enough to catch any dlls that attempt to 104 // inject after Chrome has started up. 105 content::BrowserThread::PostDelayedTask( 106 content::BrowserThread::UI, 107 FROM_HERE, 108 base::Bind(&ReportSuccessfulBlocks), 109 base::TimeDelta::FromSeconds(kBlacklistReportingDelaySec)); 110} 111 112void AddFinchBlacklistToRegistry() { 113 base::win::RegKey finch_blacklist_registry_key( 114 HKEY_CURRENT_USER, blacklist::kRegistryFinchListPath, KEY_SET_VALUE); 115 116 // No point in trying to continue if the registry key isn't valid. 117 if (!finch_blacklist_registry_key.Valid()) 118 return; 119 120 std::map<std::string, std::string> params; 121 chrome_variations::GetVariationParams(kBrowserBlacklistTrialName, ¶ms); 122 123 for (std::map<std::string, std::string>::iterator it = params.begin(); 124 it != params.end(); 125 ++it) { 126 std::wstring name = base::UTF8ToWide(it->first); 127 std::wstring val = base::UTF8ToWide(it->second); 128 129 finch_blacklist_registry_key.WriteValue(name.c_str(), val.c_str()); 130 } 131} 132 133void BrowserBlacklistBeaconSetup() { 134 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER, 135 blacklist::kRegistryBeaconPath, 136 KEY_QUERY_VALUE | KEY_SET_VALUE); 137 138 // No point in trying to continue if the registry key isn't valid. 139 if (!blacklist_registry_key.Valid()) 140 return; 141 142 // Record the results of the last blacklist setup. 143 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX; 144 blacklist_registry_key.ReadValueDW(blacklist::kBeaconState, &blacklist_state); 145 146 if (blacklist_state == blacklist::BLACKLIST_ENABLED) { 147 // The blacklist setup didn't crash, so we report if it was enabled or not. 148 if (blacklist::IsBlacklistInitialized()) { 149 RecordBlacklistSetupEvent(BLACKLIST_SETUP_RAN_SUCCESSFULLY); 150 } else { 151 // The only way for the blacklist to be enabled, but not fully 152 // initialized is if the thunk setup failed. See blacklist.cc 153 // for more details. 154 RecordBlacklistSetupEvent(BLACKLIST_THUNK_SETUP_FAILED); 155 } 156 157 // Regardless of if the blacklist was fully enabled or not, report how many 158 // times we had to try to set it up. 159 DWORD attempt_count = 0; 160 blacklist_registry_key.ReadValueDW(blacklist::kBeaconAttemptCount, 161 &attempt_count); 162 UMA_HISTOGRAM_COUNTS_100("Blacklist.RetryAttempts.Success", attempt_count); 163 } else if (blacklist_state == blacklist::BLACKLIST_SETUP_FAILED) { 164 // We can set the state to disabled without checking that the maximum number 165 // of attempts was exceeded because blacklist.cc has already done this. 166 RecordBlacklistSetupEvent(BLACKLIST_SETUP_FAILED); 167 blacklist_registry_key.WriteValue(blacklist::kBeaconState, 168 blacklist::BLACKLIST_DISABLED); 169 } else if (blacklist_state == blacklist::BLACKLIST_DISABLED) { 170 RecordBlacklistSetupEvent(BLACKLIST_SETUP_DISABLED); 171 } 172 173 // Find the last recorded blacklist version. 174 base::string16 blacklist_version; 175 blacklist_registry_key.ReadValue(blacklist::kBeaconVersion, 176 &blacklist_version); 177 178 if (blacklist_version != TEXT(CHROME_VERSION_STRING)) { 179 // The blacklist hasn't been enabled for this version yet, so enable it 180 // and reset the failure count to zero. 181 LONG set_version = blacklist_registry_key.WriteValue( 182 blacklist::kBeaconVersion, 183 TEXT(CHROME_VERSION_STRING)); 184 185 LONG set_state = blacklist_registry_key.WriteValue( 186 blacklist::kBeaconState, 187 blacklist::BLACKLIST_ENABLED); 188 189 blacklist_registry_key.WriteValue(blacklist::kBeaconAttemptCount, 190 static_cast<DWORD>(0)); 191 192 // Only report the blacklist as getting setup when both registry writes 193 // succeed, since otherwise the blacklist wasn't properly setup. 194 if (set_version == ERROR_SUCCESS && set_state == ERROR_SUCCESS) 195 RecordBlacklistSetupEvent(BLACKLIST_SETUP_ENABLED); 196 } 197} 198