CacheStorage: Remove unused interfaces from CacheStorageListener
[chromium-blink-merge.git] / chrome_elf / blacklist / blacklist.cc
blob8cb2bb1d3163a9c5045b213f168311a0623cba1c
1 // Copyright 2013 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.
5 #include "chrome_elf/blacklist/blacklist.h"
7 #include <assert.h>
8 #include <string.h>
10 #include <vector>
12 #include "base/basictypes.h"
13 #include "chrome_elf/blacklist/blacklist_interceptions.h"
14 #include "chrome_elf/chrome_elf_constants.h"
15 #include "chrome_elf/chrome_elf_util.h"
16 #include "chrome_elf/thunk_getter.h"
17 #include "sandbox/win/src/interception_internal.h"
18 #include "sandbox/win/src/internal_types.h"
19 #include "sandbox/win/src/service_resolver.h"
21 // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
22 extern "C" IMAGE_DOS_HEADER __ImageBase;
24 namespace blacklist{
26 // The DLLs listed here are known (or under strong suspicion) of causing crashes
27 // when they are loaded in the browser. DLLs should only be added to this list
28 // if there is nothing else Chrome can do to prevent those crashes.
29 // For more information about how this list is generated, and how to get off
30 // of it, see:
31 // https://sites.google.com/a/chromium.org/dev/Home/third-party-developers
32 // NOTE: Please remember to update the DllHash enum in histograms.xml when
33 // adding a new value to the blacklist.
34 const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount] = {
35 L"activedetect32.dll", // Lenovo One Key Theater.
36 // See crbug.com/379218.
37 L"activedetect64.dll", // Lenovo One Key Theater.
38 L"bitguard.dll", // Unknown (suspected malware).
39 L"chrmxtn.dll", // Unknown (keystroke logger).
40 L"cplushook.dll", // Unknown (suspected malware).
41 L"crdli.dll", // Linkury Inc.
42 L"crdli64.dll", // Linkury Inc.
43 L"datamngr.dll", // Unknown (suspected adware).
44 L"explorerex.dll", // Unknown (suspected adware).
45 L"hk.dll", // Unknown (keystroke logger).
46 L"libapi2hook.dll", // V-Bates.
47 L"libinject.dll", // V-Bates.
48 L"libinject2.dll", // V-Bates.
49 L"libredir2.dll", // V-Bates.
50 L"libsvn_tsvn32.dll", // TortoiseSVN.
51 L"libwinhook.dll", // V-Bates.
52 L"lmrn.dll", // Unknown.
53 L"minisp.dll", // Unknown (suspected malware).
54 L"minisp32.dll", // Unknown (suspected malware).
55 L"safetynut.dll", // Unknown (suspected adware).
56 L"smdmf.dll", // Unknown (suspected adware).
57 L"systemk.dll", // Unknown (suspected adware).
58 L"vntsrv.dll", // Virtual New Tab by APN LLC.
59 L"wajam_goblin_64.dll", // Wajam Internet Technologies.
60 L"wajam_goblin.dll", // Wajam Internet Technologies.
61 L"windowsapihookdll32.dll", // Lenovo One Key Theater.
62 // See crbug.com/379218.
63 L"windowsapihookdll64.dll", // Lenovo One Key Theater.
64 L"virtualcamera.ax", // %PROGRAMFILES%\ASUS\VirtualCamera.
65 // See crbug.com/422522.
66 L"ycwebcamerasource.ax", // CyberLink Youcam, crbug.com/424159
67 // Keep this null pointer here to mark the end of the list.
68 NULL,
71 bool g_blocked_dlls[kTroublesomeDllsMaxCount] = {};
72 int g_num_blocked_dlls = 0;
74 } // namespace blacklist
76 // Allocate storage for thunks in a page of this module to save on doing
77 // an extra allocation at run time.
78 #pragma section(".crthunk",read,execute)
79 __declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage;
81 namespace {
83 // Record if the blacklist was successfully initialized so processes can easily
84 // determine if the blacklist is enabled for them.
85 bool g_blacklist_initialized = false;
87 // Helper to set DWORD registry values.
88 DWORD SetDWValue(HKEY* key, const wchar_t* property, DWORD value) {
89 return ::RegSetValueEx(*key,
90 property,
92 REG_DWORD,
93 reinterpret_cast<LPBYTE>(&value),
94 sizeof(value));
97 bool GenerateStateFromBeaconAndAttemptCount(HKEY* key, DWORD blacklist_state) {
98 LONG result = 0;
99 if (blacklist_state == blacklist::BLACKLIST_ENABLED) {
100 // If the blacklist succeeded on the previous run reset the failure
101 // counter.
102 return (SetDWValue(key,
103 blacklist::kBeaconAttemptCount,
104 static_cast<DWORD>(0)) == ERROR_SUCCESS);
105 } else {
106 // Some part of the blacklist setup failed last time. If this has occured
107 // blacklist::kBeaconMaxAttempts times in a row we switch the state to
108 // failed and skip setting up the blacklist.
109 DWORD attempt_count = 0;
110 DWORD attempt_count_size = sizeof(attempt_count);
111 result = ::RegQueryValueEx(*key,
112 blacklist::kBeaconAttemptCount,
114 NULL,
115 reinterpret_cast<LPBYTE>(&attempt_count),
116 &attempt_count_size);
118 if (result == ERROR_FILE_NOT_FOUND)
119 attempt_count = 0;
120 else if (result != ERROR_SUCCESS)
121 return false;
123 ++attempt_count;
124 SetDWValue(key, blacklist::kBeaconAttemptCount, attempt_count);
126 if (attempt_count >= blacklist::kBeaconMaxAttempts) {
127 blacklist_state = blacklist::BLACKLIST_SETUP_FAILED;
128 SetDWValue(key, blacklist::kBeaconState, blacklist_state);
131 return false;
135 } // namespace
137 namespace blacklist {
139 #if defined(_WIN64)
140 // Allocate storage for the pointer to the old NtMapViewOfSectionFunction.
141 #pragma section(".oldntmap",write,read)
142 __declspec(allocate(".oldntmap"))
143 NtMapViewOfSectionFunction g_nt_map_view_of_section_func = NULL;
144 #endif
146 bool LeaveSetupBeacon() {
147 HKEY key = NULL;
148 DWORD disposition = 0;
149 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
150 kRegistryBeaconPath,
152 NULL,
153 REG_OPTION_NON_VOLATILE,
154 KEY_QUERY_VALUE | KEY_SET_VALUE,
155 NULL,
156 &key,
157 &disposition);
158 if (result != ERROR_SUCCESS)
159 return false;
161 // Retrieve the current blacklist state.
162 DWORD blacklist_state = BLACKLIST_STATE_MAX;
163 DWORD blacklist_state_size = sizeof(blacklist_state);
164 DWORD type = 0;
165 result = ::RegQueryValueEx(key,
166 kBeaconState,
168 &type,
169 reinterpret_cast<LPBYTE>(&blacklist_state),
170 &blacklist_state_size);
172 if (result != ERROR_SUCCESS || blacklist_state == BLACKLIST_DISABLED ||
173 type != REG_DWORD) {
174 ::RegCloseKey(key);
175 return false;
178 if (!GenerateStateFromBeaconAndAttemptCount(&key, blacklist_state)) {
179 ::RegCloseKey(key);
180 return false;
183 result = SetDWValue(&key, kBeaconState, BLACKLIST_SETUP_RUNNING);
184 ::RegCloseKey(key);
186 return (result == ERROR_SUCCESS);
189 bool ResetBeacon() {
190 HKEY key = NULL;
191 DWORD disposition = 0;
192 LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
193 kRegistryBeaconPath,
195 NULL,
196 REG_OPTION_NON_VOLATILE,
197 KEY_QUERY_VALUE | KEY_SET_VALUE,
198 NULL,
199 &key,
200 &disposition);
201 if (result != ERROR_SUCCESS)
202 return false;
204 DWORD blacklist_state = BLACKLIST_STATE_MAX;
205 DWORD blacklist_state_size = sizeof(blacklist_state);
206 DWORD type = 0;
207 result = ::RegQueryValueEx(key,
208 kBeaconState,
210 &type,
211 reinterpret_cast<LPBYTE>(&blacklist_state),
212 &blacklist_state_size);
214 if (result != ERROR_SUCCESS || type != REG_DWORD) {
215 ::RegCloseKey(key);
216 return false;
219 // Reaching this point with the setup running state means the setup did not
220 // crash, so we reset to enabled. Any other state indicates that setup was
221 // skipped; in that case we leave the state alone for later recording.
222 if (blacklist_state == BLACKLIST_SETUP_RUNNING)
223 result = SetDWValue(&key, kBeaconState, BLACKLIST_ENABLED);
225 ::RegCloseKey(key);
226 return (result == ERROR_SUCCESS);
229 int BlacklistSize() {
230 int size = -1;
231 while (blacklist::g_troublesome_dlls[++size] != NULL) {}
233 return size;
236 bool IsBlacklistInitialized() {
237 return g_blacklist_initialized;
240 int GetBlacklistIndex(const wchar_t* dll_name) {
241 for (int i = 0; i < kTroublesomeDllsMaxCount && g_troublesome_dlls[i]; ++i) {
242 if (_wcsicmp(dll_name, g_troublesome_dlls[i]) == 0)
243 return i;
245 return -1;
248 bool AddDllToBlacklist(const wchar_t* dll_name) {
249 int blacklist_size = BlacklistSize();
250 // We need to leave one space at the end for the null pointer.
251 if (blacklist_size + 1 >= kTroublesomeDllsMaxCount)
252 return false;
253 for (int i = 0; i < blacklist_size; ++i) {
254 if (!_wcsicmp(g_troublesome_dlls[i], dll_name))
255 return true;
258 // Copy string to blacklist.
259 wchar_t* str_buffer = new wchar_t[wcslen(dll_name) + 1];
260 wcscpy(str_buffer, dll_name);
262 g_troublesome_dlls[blacklist_size] = str_buffer;
263 g_blocked_dlls[blacklist_size] = false;
264 return true;
267 bool RemoveDllFromBlacklist(const wchar_t* dll_name) {
268 int blacklist_size = BlacklistSize();
269 for (int i = 0; i < blacklist_size; ++i) {
270 if (!_wcsicmp(g_troublesome_dlls[i], dll_name)) {
271 // Found the thing to remove. Delete it then replace it with the last
272 // element.
273 delete[] g_troublesome_dlls[i];
274 g_troublesome_dlls[i] = g_troublesome_dlls[blacklist_size - 1];
275 g_troublesome_dlls[blacklist_size - 1] = NULL;
277 // Also update the stats recording if we have blocked this dll or not.
278 if (g_blocked_dlls[i])
279 --g_num_blocked_dlls;
280 g_blocked_dlls[i] = g_blocked_dlls[blacklist_size - 1];
281 return true;
284 return false;
287 // TODO(csharp): Maybe store these values in the registry so we can
288 // still report them if Chrome crashes early.
289 void SuccessfullyBlocked(const wchar_t** blocked_dlls, int* size) {
290 if (size == NULL)
291 return;
293 // If the array isn't valid or big enough, just report the size it needs to
294 // be and return.
295 if (blocked_dlls == NULL && *size < g_num_blocked_dlls) {
296 *size = g_num_blocked_dlls;
297 return;
300 *size = g_num_blocked_dlls;
302 int strings_to_fill = 0;
303 for (int i = 0; strings_to_fill < g_num_blocked_dlls && g_troublesome_dlls[i];
304 ++i) {
305 if (g_blocked_dlls[i]) {
306 blocked_dlls[strings_to_fill] = g_troublesome_dlls[i];
307 ++strings_to_fill;
312 void BlockedDll(size_t blocked_index) {
313 assert(blocked_index < kTroublesomeDllsMaxCount);
315 if (!g_blocked_dlls[blocked_index] &&
316 blocked_index < kTroublesomeDllsMaxCount) {
317 ++g_num_blocked_dlls;
318 g_blocked_dlls[blocked_index] = true;
322 bool Initialize(bool force) {
323 // Check to see that we found the functions we need in ntdll.
324 if (!InitializeInterceptImports())
325 return false;
327 // Check to see if this is a non-browser process, abort if so.
328 if (IsNonBrowserProcess())
329 return false;
331 // Check to see if the blacklist beacon is still set to running (indicating a
332 // failure) or disabled, and abort if so.
333 if (!force && !LeaveSetupBeacon())
334 return false;
336 // It is possible for other dlls to have already patched code by now and
337 // attempting to patch their code might result in crashes.
338 const bool kRelaxed = false;
340 // Create a thunk via the appropriate ServiceResolver instance.
341 sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed);
343 // Don't try blacklisting on unsupported OS versions.
344 if (!thunk)
345 return false;
347 BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage);
349 // Mark the thunk storage as readable and writeable, since we
350 // ready to write to it.
351 DWORD old_protect = 0;
352 if (!VirtualProtect(&g_thunk_storage,
353 sizeof(g_thunk_storage),
354 PAGE_EXECUTE_READWRITE,
355 &old_protect)) {
356 return false;
359 thunk->AllowLocalPatches();
361 // We declare this early so it can be used in the 64-bit block below and
362 // still work on 32-bit build when referenced at the end of the function.
363 BOOL page_executable = false;
365 // Replace the default NtMapViewOfSection with our patched version.
366 #if defined(_WIN64)
367 NTSTATUS ret = thunk->Setup(::GetModuleHandle(sandbox::kNtdllName),
368 reinterpret_cast<void*>(&__ImageBase),
369 "NtMapViewOfSection",
370 NULL,
371 &blacklist::BlNtMapViewOfSection64,
372 thunk_storage,
373 sizeof(sandbox::ThunkData),
374 NULL);
376 // Keep a pointer to the original code, we don't have enough space to
377 // add it directly to the call.
378 g_nt_map_view_of_section_func = reinterpret_cast<NtMapViewOfSectionFunction>(
379 thunk_storage);
381 // Ensure that the pointer to the old function can't be changed.
382 page_executable = VirtualProtect(&g_nt_map_view_of_section_func,
383 sizeof(g_nt_map_view_of_section_func),
384 PAGE_EXECUTE_READ,
385 &old_protect);
386 #else
387 NTSTATUS ret = thunk->Setup(::GetModuleHandle(sandbox::kNtdllName),
388 reinterpret_cast<void*>(&__ImageBase),
389 "NtMapViewOfSection",
390 NULL,
391 &blacklist::BlNtMapViewOfSection,
392 thunk_storage,
393 sizeof(sandbox::ThunkData),
394 NULL);
395 #endif
396 delete thunk;
398 // Record if we have initialized the blacklist.
399 g_blacklist_initialized = NT_SUCCESS(ret);
401 // Mark the thunk storage as executable and prevent any future writes to it.
402 page_executable = page_executable && VirtualProtect(&g_thunk_storage,
403 sizeof(g_thunk_storage),
404 PAGE_EXECUTE_READ,
405 &old_protect);
407 AddDllsFromRegistryToBlacklist();
409 return NT_SUCCESS(ret) && page_executable;
412 void AddDllsFromRegistryToBlacklist() {
413 HKEY key = NULL;
414 LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
415 kRegistryFinchListPath,
417 KEY_QUERY_VALUE | KEY_SET_VALUE,
418 &key);
420 if (result != ERROR_SUCCESS)
421 return;
423 // We add dlls from the registry to the blacklist.
424 DWORD value_len;
425 DWORD name_len = MAX_PATH;
426 std::vector<wchar_t> name_buffer(name_len);
427 for (int i = 0; result == ERROR_SUCCESS; ++i) {
428 name_len = MAX_PATH;
429 value_len = 0;
430 result = ::RegEnumValue(
431 key, i, &name_buffer[0], &name_len, NULL, NULL, NULL, &value_len);
432 if (result != ERROR_SUCCESS)
433 break;
435 name_len = name_len + 1;
436 value_len = value_len + 1;
437 std::vector<wchar_t> value_buffer(value_len);
438 result = ::RegEnumValue(key, i, &name_buffer[0], &name_len, NULL, NULL,
439 reinterpret_cast<BYTE*>(&value_buffer[0]),
440 &value_len);
441 if (result != ERROR_SUCCESS)
442 break;
443 value_buffer[value_len - 1] = L'\0';
444 AddDllToBlacklist(&value_buffer[0]);
447 ::RegCloseKey(key);
448 return;
451 } // namespace blacklist