chrome_elf_init_win.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 // Deprecated. The blacklist thunk setup code failed to execute. 44 BLACKLIST_THUNK_SETUP_FAILED, 45 46 // Deprecated. The blacklist interception code failed to execute. 47 BLACKLIST_INTERCEPTION_FAILED, 48 49 // The blacklist was disabled for this run (after it failed too many times). 50 BLACKLIST_SETUP_DISABLED, 51 52 // Always keep this at the end. 53 BLACKLIST_SETUP_EVENT_MAX, 54}; 55 56void RecordBlacklistSetupEvent(BlacklistSetupEventType blacklist_setup_event) { 57 UMA_HISTOGRAM_ENUMERATION("Blacklist.Setup", 58 blacklist_setup_event, 59 BLACKLIST_SETUP_EVENT_MAX); 60} 61 62// Report which DLLs were prevented from being loaded. 63void ReportSuccessfulBlocks() { 64 // Figure out how many dlls were blocked. 65 int num_blocked_dlls = 0; 66 blacklist::SuccessfullyBlocked(NULL, &num_blocked_dlls); 67 68 if (num_blocked_dlls == 0) 69 return; 70 71 // Now retrieve the list of blocked dlls. 72 std::vector<const wchar_t*> blocked_dlls(num_blocked_dlls); 73 blacklist::SuccessfullyBlocked(&blocked_dlls[0], &num_blocked_dlls); 74 75 // Send up the hashes of the blocked dlls via UMA. 76 for (size_t i = 0; i < blocked_dlls.size(); ++i) { 77 std::string dll_name_utf8; 78 base::WideToUTF8(blocked_dlls[i], wcslen(blocked_dlls[i]), &dll_name_utf8); 79 int uma_hash = DllNameToHash(dll_name_utf8); 80 81 UMA_HISTOGRAM_SPARSE_SLOWLY("Blacklist.Blocked", uma_hash); 82 } 83} 84 85} // namespace 86 87void InitializeChromeElf() { 88 if (base::FieldTrialList::FindFullName(kBrowserBlacklistTrialName) == 89 kBrowserBlacklistTrialDisabledGroupName) { 90 // Disable the blacklist for all future runs by removing the beacon. 91 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER); 92 blacklist_registry_key.DeleteKey(blacklist::kRegistryBeaconPath); 93 } else { 94 AddFinchBlacklistToRegistry(); 95 BrowserBlacklistBeaconSetup(); 96 } 97 98 // Report all successful blacklist interceptions. 99 ReportSuccessfulBlocks(); 100 101 // Schedule another task to report all sucessful interceptions later. 102 // This time delay should be long enough to catch any dlls that attempt to 103 // inject after Chrome has started up. 104 content::BrowserThread::PostDelayedTask( 105 content::BrowserThread::UI, 106 FROM_HERE, 107 base::Bind(&ReportSuccessfulBlocks), 108 base::TimeDelta::FromSeconds(kBlacklistReportingDelaySec)); 109} 110 111void AddFinchBlacklistToRegistry() { 112 base::win::RegKey finch_blacklist_registry_key( 113 HKEY_CURRENT_USER, blacklist::kRegistryFinchListPath, KEY_SET_VALUE); 114 115 // No point in trying to continue if the registry key isn't valid. 116 if (!finch_blacklist_registry_key.Valid()) 117 return; 118 119 std::map<std::string, std::string> params; 120 chrome_variations::GetVariationParams(kBrowserBlacklistTrialName, ¶ms); 121 122 for (std::map<std::string, std::string>::iterator it = params.begin(); 123 it != params.end(); 124 ++it) { 125 std::wstring name = base::UTF8ToWide(it->first); 126 std::wstring val = base::UTF8ToWide(it->second); 127 128 finch_blacklist_registry_key.WriteValue(name.c_str(), val.c_str()); 129 } 130} 131 132void BrowserBlacklistBeaconSetup() { 133 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER, 134 blacklist::kRegistryBeaconPath, 135 KEY_QUERY_VALUE | KEY_SET_VALUE); 136 137 // No point in trying to continue if the registry key isn't valid. 138 if (!blacklist_registry_key.Valid()) 139 return; 140 141 // Record the results of the last blacklist setup. 142 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX; 143 blacklist_registry_key.ReadValueDW(blacklist::kBeaconState, &blacklist_state); 144 145 if (blacklist_state == blacklist::BLACKLIST_ENABLED) { 146 // The blacklist was enabled successfully so we record the event (along with 147 // the number of failed previous attempts). 148 RecordBlacklistSetupEvent(BLACKLIST_SETUP_RAN_SUCCESSFULLY); 149 DWORD attempt_count = 0; 150 blacklist_registry_key.ReadValueDW(blacklist::kBeaconAttemptCount, 151 &attempt_count); 152 UMA_HISTOGRAM_COUNTS_100("Blacklist.RetryAttempts.Success", attempt_count); 153 } else if (blacklist_state == blacklist::BLACKLIST_SETUP_FAILED) { 154 // We can set the state to disabled without checking that the maximum number 155 // of attempts was exceeded because blacklist.cc has already done this. 156 RecordBlacklistSetupEvent(BLACKLIST_SETUP_FAILED); 157 blacklist_registry_key.WriteValue(blacklist::kBeaconState, 158 blacklist::BLACKLIST_DISABLED); 159 } else if (blacklist_state == blacklist::BLACKLIST_DISABLED) { 160 RecordBlacklistSetupEvent(BLACKLIST_SETUP_DISABLED); 161 } 162 163 // Find the last recorded blacklist version. 164 base::string16 blacklist_version; 165 blacklist_registry_key.ReadValue(blacklist::kBeaconVersion, 166 &blacklist_version); 167 168 if (blacklist_version != TEXT(CHROME_VERSION_STRING)) { 169 // The blacklist hasn't been enabled for this version yet, so enable it 170 // and reset the failure count to zero. 171 LONG set_version = blacklist_registry_key.WriteValue( 172 blacklist::kBeaconVersion, 173 TEXT(CHROME_VERSION_STRING)); 174 175 LONG set_state = blacklist_registry_key.WriteValue( 176 blacklist::kBeaconState, 177 blacklist::BLACKLIST_ENABLED); 178 179 blacklist_registry_key.WriteValue(blacklist::kBeaconAttemptCount, 180 static_cast<DWORD>(0)); 181 182 // Only report the blacklist as getting setup when both registry writes 183 // succeed, since otherwise the blacklist wasn't properly setup. 184 if (set_version == ERROR_SUCCESS && set_state == ERROR_SUCCESS) 185 RecordBlacklistSetupEvent(BLACKLIST_SETUP_ENABLED); 186 } 187} 188