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