chrome_elf_init_win.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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 "content/public/browser/browser_thread.h" 16#include "version.h" // NOLINT 17 18namespace { 19 20const char kBrowserBlacklistTrialName[] = "BrowserBlacklist"; 21const char kBrowserBlacklistTrialEnabledGroupName[] = "Enabled"; 22 23// How long to wait, in seconds, before reporting for the second (and last 24// time), what dlls were blocked from the browser process. 25const int kBlacklistReportingDelaySec = 600; 26 27// This enum is used to define the buckets for an enumerated UMA histogram. 28// Hence, 29// (a) existing enumerated constants should never be deleted or reordered, and 30// (b) new constants should only be appended in front of 31// BLACKLIST_SETUP_EVENT_MAX. 32enum BlacklistSetupEventType { 33 // The blacklist beacon has placed to enable the browser blacklisting. 34 BLACKLIST_SETUP_ENABLED = 0, 35 36 // The blacklist was successfully enabled. 37 BLACKLIST_SETUP_RAN_SUCCESSFULLY, 38 39 // The blacklist setup code failed to execute. 40 BLACKLIST_SETUP_FAILED, 41 42 // The blacklist thunk setup code failed to execute. 43 BLACKLIST_THUNK_SETUP_FAILED, 44 45 // The blacklist interception code failed to execute. 46 BLACKLIST_INTERCEPTION_FAILED, 47 48 // Always keep this at the end. 49 BLACKLIST_SETUP_EVENT_MAX, 50}; 51 52void RecordBlacklistSetupEvent(BlacklistSetupEventType blacklist_setup_event) { 53 UMA_HISTOGRAM_ENUMERATION("Blacklist.Setup", 54 blacklist_setup_event, 55 BLACKLIST_SETUP_EVENT_MAX); 56} 57 58// Report which DLLs were prevented from being loaded. 59void ReportSuccessfulBlocks() { 60 // Figure out how many dlls were blocked. 61 int num_blocked_dlls = 0; 62 blacklist::SuccessfullyBlocked(NULL, &num_blocked_dlls); 63 64 if (num_blocked_dlls == 0) 65 return; 66 67 // Now retrieve the list of blocked dlls. 68 std::vector<const wchar_t*> blocked_dlls(num_blocked_dlls); 69 blacklist::SuccessfullyBlocked(&blocked_dlls[0], &num_blocked_dlls); 70 71 // Send up the hashes of the blocked dlls via UMA. 72 for (size_t i = 0; i < blocked_dlls.size(); ++i) { 73 std::string dll_name_utf8; 74 base::WideToUTF8(blocked_dlls[i], wcslen(blocked_dlls[i]), &dll_name_utf8); 75 int uma_hash = DllNameToHash(dll_name_utf8); 76 77 UMA_HISTOGRAM_SPARSE_SLOWLY("Blacklist.Blocked", uma_hash); 78 } 79} 80 81} // namespace 82 83void InitializeChromeElf() { 84 if (base::FieldTrialList::FindFullName(kBrowserBlacklistTrialName) == 85 kBrowserBlacklistTrialEnabledGroupName) { 86 BrowserBlacklistBeaconSetup(); 87 } else { 88 // Disable the blacklist for all future runs by removing the beacon. 89 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER); 90 blacklist_registry_key.DeleteKey(blacklist::kRegistryBeaconPath); 91 } 92 93 // Report all successful blacklist interceptions. 94 ReportSuccessfulBlocks(); 95 96 // Schedule another task to report all sucessful interceptions later. 97 // This time delay should be long enough to catch any dlls that attempt to 98 // inject after Chrome has started up. 99 content::BrowserThread::PostDelayedTask( 100 content::BrowserThread::UI, 101 FROM_HERE, 102 base::Bind(&ReportSuccessfulBlocks), 103 base::TimeDelta::FromSeconds(kBlacklistReportingDelaySec)); 104} 105 106void BrowserBlacklistBeaconSetup() { 107 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER, 108 blacklist::kRegistryBeaconPath, 109 KEY_QUERY_VALUE | KEY_SET_VALUE); 110 111 // No point in trying to continue if the registry key isn't valid. 112 if (!blacklist_registry_key.Valid()) 113 return; 114 115 // Record the results of the last blacklist setup. 116 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX; 117 blacklist_registry_key.ReadValueDW(blacklist::kBeaconState, &blacklist_state); 118 119 if (blacklist_state == blacklist::BLACKLIST_ENABLED) { 120 RecordBlacklistSetupEvent(BLACKLIST_SETUP_RAN_SUCCESSFULLY); 121 } else { 122 switch (blacklist_state) { 123 case blacklist::BLACKLIST_SETUP_RUNNING: 124 RecordBlacklistSetupEvent(BLACKLIST_SETUP_FAILED); 125 break; 126 case blacklist::BLACKLIST_THUNK_SETUP: 127 RecordBlacklistSetupEvent(BLACKLIST_THUNK_SETUP_FAILED); 128 break; 129 case blacklist::BLACKLIST_INTERCEPTING: 130 RecordBlacklistSetupEvent(BLACKLIST_INTERCEPTION_FAILED); 131 break; 132 } 133 134 // Since some part of the blacklist failed, mark it as disabled 135 // for this version. 136 if (blacklist_state != blacklist::BLACKLIST_DISABLED) { 137 blacklist_registry_key.WriteValue(blacklist::kBeaconState, 138 blacklist::BLACKLIST_DISABLED); 139 } 140 } 141 142 // Find the last recorded blacklist version. 143 base::string16 blacklist_version; 144 blacklist_registry_key.ReadValue(blacklist::kBeaconVersion, 145 &blacklist_version); 146 147 if (blacklist_version != TEXT(CHROME_VERSION_STRING)) { 148 // The blacklist hasn't been enabled for this version yet, so enable it. 149 LONG set_version = blacklist_registry_key.WriteValue( 150 blacklist::kBeaconVersion, 151 TEXT(CHROME_VERSION_STRING)); 152 153 LONG set_state = blacklist_registry_key.WriteValue( 154 blacklist::kBeaconState, 155 blacklist::BLACKLIST_ENABLED); 156 157 // Only report the blacklist as getting setup when both registry writes 158 // succeed, since otherwise the blacklist wasn't properly setup. 159 if (set_version == ERROR_SUCCESS && set_state == ERROR_SUCCESS) 160 RecordBlacklistSetupEvent(BLACKLIST_SETUP_ENABLED); 161 } 162} 163