Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chrome_elf_init_win.cc
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
19 const char kBrowserBlacklistTrialName[] = "BrowserBlacklist";
20 const char kBrowserBlacklistTrialDisabledGroupName[] = "NoBlacklist";
21
22 namespace {
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.
26 const 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.
33 enum 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
57 void 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.
64 void 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
88 void 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
112 // Note that running multiple chrome instances with distinct user data
113 // directories could lead to deletion (and/or replacement) of the finch
114 // blacklist registry data in one instance before the second has a chance to
115 // read those values.
116 void AddFinchBlacklistToRegistry() {
117   base::win::RegKey finch_blacklist_registry_key(
118       HKEY_CURRENT_USER, blacklist::kRegistryFinchListPath, KEY_SET_VALUE);
119
120   // No point in trying to continue if the registry key isn't valid.
121   if (!finch_blacklist_registry_key.Valid())
122     return;
123
124   // Delete and recreate the key to clear the registry.
125   finch_blacklist_registry_key.DeleteKey(L"");
126   finch_blacklist_registry_key.Create(
127       HKEY_CURRENT_USER, blacklist::kRegistryFinchListPath, KEY_SET_VALUE);
128
129   std::map<std::string, std::string> params;
130   variations::GetVariationParams(kBrowserBlacklistTrialName, &params);
131
132   for (std::map<std::string, std::string>::iterator it = params.begin();
133        it != params.end();
134        ++it) {
135     std::wstring name = base::UTF8ToWide(it->first);
136     std::wstring val = base::UTF8ToWide(it->second);
137
138     finch_blacklist_registry_key.WriteValue(name.c_str(), val.c_str());
139   }
140 }
141
142 void BrowserBlacklistBeaconSetup() {
143   base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER,
144                                            blacklist::kRegistryBeaconPath,
145                                            KEY_QUERY_VALUE | KEY_SET_VALUE);
146
147   // No point in trying to continue if the registry key isn't valid.
148   if (!blacklist_registry_key.Valid())
149     return;
150
151   // Record the results of the last blacklist setup.
152   DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX;
153   blacklist_registry_key.ReadValueDW(blacklist::kBeaconState, &blacklist_state);
154
155   if (blacklist_state == blacklist::BLACKLIST_ENABLED) {
156     // The blacklist setup didn't crash, so we report if it was enabled or not.
157     if (blacklist::IsBlacklistInitialized()) {
158       RecordBlacklistSetupEvent(BLACKLIST_SETUP_RAN_SUCCESSFULLY);
159     } else {
160       // The only way for the blacklist to be enabled, but not fully
161       // initialized is if the thunk setup failed. See blacklist.cc
162       // for more details.
163       RecordBlacklistSetupEvent(BLACKLIST_THUNK_SETUP_FAILED);
164     }
165
166     // Regardless of if the blacklist was fully enabled or not, report how many
167     // times we had to try to set it up.
168     DWORD attempt_count = 0;
169     blacklist_registry_key.ReadValueDW(blacklist::kBeaconAttemptCount,
170                                        &attempt_count);
171     UMA_HISTOGRAM_COUNTS_100("Blacklist.RetryAttempts.Success", attempt_count);
172   } else if (blacklist_state == blacklist::BLACKLIST_SETUP_FAILED) {
173     // We can set the state to disabled without checking that the maximum number
174     // of attempts was exceeded because blacklist.cc has already done this.
175     RecordBlacklistSetupEvent(BLACKLIST_SETUP_FAILED);
176     blacklist_registry_key.WriteValue(blacklist::kBeaconState,
177                                       blacklist::BLACKLIST_DISABLED);
178   } else if (blacklist_state == blacklist::BLACKLIST_DISABLED) {
179     RecordBlacklistSetupEvent(BLACKLIST_SETUP_DISABLED);
180   }
181
182   // Find the last recorded blacklist version.
183   base::string16 blacklist_version;
184   blacklist_registry_key.ReadValue(blacklist::kBeaconVersion,
185                                    &blacklist_version);
186
187   if (blacklist_version != TEXT(CHROME_VERSION_STRING)) {
188     // The blacklist hasn't been enabled for this version yet, so enable it
189     // and reset the failure count to zero.
190     LONG set_version = blacklist_registry_key.WriteValue(
191         blacklist::kBeaconVersion,
192         TEXT(CHROME_VERSION_STRING));
193
194     LONG set_state = blacklist_registry_key.WriteValue(
195         blacklist::kBeaconState,
196         blacklist::BLACKLIST_ENABLED);
197
198     blacklist_registry_key.WriteValue(blacklist::kBeaconAttemptCount,
199                                       static_cast<DWORD>(0));
200
201     // Only report the blacklist as getting setup when both registry writes
202     // succeed, since otherwise the blacklist wasn't properly setup.
203     if (set_version == ERROR_SUCCESS && set_state == ERROR_SUCCESS)
204       RecordBlacklistSetupEvent(BLACKLIST_SETUP_ENABLED);
205   }
206 }