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, &params);
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