summaryrefslogtreecommitdiff
path: root/chromium/chrome_elf
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/chrome_elf
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
downloadqtwebengine-chromium-ab0a50979b9eb4dfa3320eff7e187e41efedf7a9.tar.gz
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/chrome_elf')
-rw-r--r--chromium/chrome_elf/DEPS2
-rw-r--r--chromium/chrome_elf/OWNERS3
-rw-r--r--chromium/chrome_elf/README15
-rw-r--r--chromium/chrome_elf/blacklist.gypi66
-rw-r--r--chromium/chrome_elf/blacklist/OWNERS3
-rw-r--r--chromium/chrome_elf/blacklist/blacklist.cc427
-rw-r--r--chromium/chrome_elf/blacklist/blacklist.h78
-rw-r--r--chromium/chrome_elf/blacklist/blacklist_interceptions.cc276
-rw-r--r--chromium/chrome_elf/blacklist/blacklist_interceptions.h43
-rw-r--r--chromium/chrome_elf/breakpad.cc178
-rw-r--r--chromium/chrome_elf/breakpad.h34
-rw-r--r--chromium/chrome_elf/chrome_elf.def6
-rw-r--r--chromium/chrome_elf/chrome_elf.gyp166
-rw-r--r--chromium/chrome_elf/chrome_elf.ver2
-rw-r--r--chromium/chrome_elf/chrome_elf_constants.cc28
-rw-r--r--chromium/chrome_elf/chrome_elf_constants.h51
-rw-r--r--chromium/chrome_elf/chrome_elf_main.cc19
-rw-r--r--chromium/chrome_elf/chrome_elf_main.h2
-rw-r--r--chromium/chrome_elf/chrome_elf_util.cc209
-rw-r--r--chromium/chrome_elf/chrome_elf_util.h31
-rw-r--r--chromium/chrome_elf/chrome_elf_util_unittest.cc186
-rw-r--r--chromium/chrome_elf/chrome_exe_manifest.template10
-rw-r--r--chromium/chrome_elf/chrome_exe_manifest_action.gypi34
-rw-r--r--chromium/chrome_elf/chrome_redirects.def9
-rw-r--r--chromium/chrome_elf/chrome_redirects_main.cc14
-rw-r--r--chromium/chrome_elf/create_file/chrome_create_file.cc330
-rw-r--r--chromium/chrome_elf/create_file/chrome_create_file.h41
-rw-r--r--chromium/chrome_elf/create_file/chrome_create_file_unittest.cc408
-rw-r--r--chromium/chrome_elf/dll_hash.gypi31
-rw-r--r--chromium/chrome_elf/dll_hash/dll_hash.cc14
-rw-r--r--chromium/chrome_elf/dll_hash/dll_hash.h13
-rw-r--r--chromium/chrome_elf/dll_hash/dll_hash_main.cc28
-rw-r--r--chromium/chrome_elf/elf_imports_unittest.cc101
-rw-r--r--chromium/chrome_elf/ntdll_cache.cc110
-rw-r--r--chromium/chrome_elf/ntdll_cache.h6
-rw-r--r--chromium/chrome_elf/thunk_getter.cc142
-rw-r--r--chromium/chrome_elf/thunk_getter.h16
-rw-r--r--chromium/chrome_elf/version_assembly_manifest.template8
-rw-r--r--chromium/chrome_elf/version_assembly_manifest_action.gypi37
39 files changed, 3021 insertions, 156 deletions
diff --git a/chromium/chrome_elf/DEPS b/chromium/chrome_elf/DEPS
index 48e88750d4a..495665e10bf 100644
--- a/chromium/chrome_elf/DEPS
+++ b/chromium/chrome_elf/DEPS
@@ -1,2 +1,4 @@
include_rules = [
+ "+sandbox",
+ "+breakpad/src/client",
]
diff --git a/chromium/chrome_elf/OWNERS b/chromium/chrome_elf/OWNERS
index d2e52d6c15f..3d69bab21a6 100644
--- a/chromium/chrome_elf/OWNERS
+++ b/chromium/chrome_elf/OWNERS
@@ -1,3 +1,2 @@
caitkp@chromium.org
- gab@chromium.org
- robertshield@chromium.org \ No newline at end of file
+ robertshield@chromium.org
diff --git a/chromium/chrome_elf/README b/chromium/chrome_elf/README
deleted file mode 100644
index b6574373756..00000000000
--- a/chromium/chrome_elf/README
+++ /dev/null
@@ -1,15 +0,0 @@
-Chrome Early Loading Framework (aka ChromeELF)
-
-chrome_elf.dll is shipped in Chrome's version directory to ease updates,
-and is loaded early in chrome.exe's lifetime. This is done by turning the
-version directory into a private assembly which refers to chrome_elf.dll
-(http://msdn.microsoft.com/library/aa374224.aspx).
-
-In an ideal world, this would be done by embedding an application config in
-chrome.exe that would refer to the proper version directory via a
-probing\privatePath attribute (http://msdn.microsoft.com/library/aa374182.aspx).
-This would allow us to refer to dlls in the version directory without having to
-make the version directory itself into an assembly. It would also avoid naming
-conflicts (as the WinSxS dir and GAC both take precedence over private
-assemblies when searching for dlls). Unfortunately, the probing\privatePath
-attribute is only supported for Windows 7 and later.
diff --git a/chromium/chrome_elf/blacklist.gypi b/chromium/chrome_elf/blacklist.gypi
new file mode 100644
index 00000000000..7ab5be1aaac
--- /dev/null
+++ b/chromium/chrome_elf/blacklist.gypi
@@ -0,0 +1,66 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'targets': [
+ {
+ 'target_name': 'blacklist',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '..',
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ],
+ 'sources': [
+ 'blacklist/blacklist.cc',
+ 'blacklist/blacklist.h',
+ 'blacklist/blacklist_interceptions.cc',
+ 'blacklist/blacklist_interceptions.h',
+ ],
+ 'dependencies': [
+ # Depend on base_static, but do NOT take a dependency on base.gyp:base
+ # as that would risk pulling in base's link-time dependencies which
+ # chrome_elf cannot do.
+ '../base/base.gyp:base_static',
+ '../chrome_elf/chrome_elf.gyp:chrome_elf_breakpad',
+ '../chrome_elf/chrome_elf.gyp:chrome_elf_constants',
+ '../sandbox/sandbox.gyp:sandbox',
+ ],
+ },
+ {
+ 'target_name': 'blacklist_test_main_dll',
+ 'type': 'shared_library',
+ 'sources': [
+ 'blacklist/test/blacklist_test_main_dll.cc',
+ 'blacklist/test/blacklist_test_main_dll.def',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ 'blacklist',
+ ],
+ },
+ {
+ 'target_name': 'blacklist_test_dll_1',
+ 'type': 'loadable_module',
+ 'sources': [
+ 'blacklist/test/blacklist_test_dll_1.cc',
+ 'blacklist/test/blacklist_test_dll_1.def',
+ ],
+ },
+ {
+ 'target_name': 'blacklist_test_dll_2',
+ 'type': 'loadable_module',
+ 'sources': [
+ 'blacklist/test/blacklist_test_dll_2.cc',
+ 'blacklist/test/blacklist_test_dll_2.def',
+ ],
+ },
+ {
+ 'target_name': 'blacklist_test_dll_3',
+ 'type': 'loadable_module',
+ 'sources': [
+ 'blacklist/test/blacklist_test_dll_3.cc',
+ ],
+ },
+ ],
+}
+
diff --git a/chromium/chrome_elf/blacklist/OWNERS b/chromium/chrome_elf/blacklist/OWNERS
new file mode 100644
index 00000000000..28a6a305588
--- /dev/null
+++ b/chromium/chrome_elf/blacklist/OWNERS
@@ -0,0 +1,3 @@
+caitkp@chromium.org
+csharp@chromium.org
+robertshield@chromium.org
diff --git a/chromium/chrome_elf/blacklist/blacklist.cc b/chromium/chrome_elf/blacklist/blacklist.cc
new file mode 100644
index 00000000000..efb9c97cd20
--- /dev/null
+++ b/chromium/chrome_elf/blacklist/blacklist.cc
@@ -0,0 +1,427 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_elf/blacklist/blacklist.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "chrome_elf/blacklist/blacklist_interceptions.h"
+#include "chrome_elf/chrome_elf_constants.h"
+#include "chrome_elf/chrome_elf_util.h"
+#include "chrome_elf/thunk_getter.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/service_resolver.h"
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+namespace blacklist{
+
+// The DLLs listed here are known (or under strong suspicion) of causing crashes
+// when they are loaded in the browser. DLLs should only be added to this list
+// if there is nothing else Chrome can do to prevent those crashes.
+// For more information about how this list is generated, and how to get off
+// of it, see:
+// https://sites.google.com/a/chromium.org/dev/Home/third-party-developers
+const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount] = {
+ L"activedetect32.dll", // Lenovo One Key Theater.
+ // See crbug.com/379218.
+ L"activedetect64.dll", // Lenovo One Key Theater.
+ L"bitguard.dll", // Unknown (suspected malware).
+ L"chrmxtn.dll", // Unknown (keystroke logger).
+ L"datamngr.dll", // Unknown (suspected adware).
+ L"hk.dll", // Unknown (keystroke logger).
+ L"libsvn_tsvn32.dll", // TortoiseSVN.
+ L"lmrn.dll", // Unknown.
+ L"scdetour.dll", // Quick Heal Antivirus.
+ // See crbug.com/382561.
+ L"systemk.dll", // Unknown (suspected adware).
+ L"windowsapihookdll32.dll", // Lenovo One Key Theater.
+ // See crbug.com/379218.
+ L"windowsapihookdll64.dll", // Lenovo One Key Theater.
+ // Keep this null pointer here to mark the end of the list.
+ NULL,
+};
+
+bool g_blocked_dlls[kTroublesomeDllsMaxCount] = {};
+int g_num_blocked_dlls = 0;
+
+} // namespace blacklist
+
+// Allocate storage for thunks in a page of this module to save on doing
+// an extra allocation at run time.
+#pragma section(".crthunk",read,execute)
+__declspec(allocate(".crthunk")) sandbox::ThunkData g_thunk_storage;
+
+namespace {
+
+// Record if the blacklist was successfully initialized so processes can easily
+// determine if the blacklist is enabled for them.
+bool g_blacklist_initialized = false;
+
+// Helper to set DWORD registry values.
+DWORD SetDWValue(HKEY* key, const wchar_t* property, DWORD value) {
+ return ::RegSetValueEx(*key,
+ property,
+ 0,
+ REG_DWORD,
+ reinterpret_cast<LPBYTE>(&value),
+ sizeof(value));
+}
+
+bool GenerateStateFromBeaconAndAttemptCount(HKEY* key, DWORD blacklist_state) {
+ LONG result = 0;
+ if (blacklist_state == blacklist::BLACKLIST_SETUP_RUNNING) {
+ // Some part of the blacklist setup failed last time. If this has occured
+ // blacklist::kBeaconMaxAttempts times in a row we switch the state to
+ // failed and skip setting up the blacklist.
+ DWORD attempt_count = 0;
+ DWORD attempt_count_size = sizeof(attempt_count);
+ result = ::RegQueryValueEx(*key,
+ blacklist::kBeaconAttemptCount,
+ 0,
+ NULL,
+ reinterpret_cast<LPBYTE>(&attempt_count),
+ &attempt_count_size);
+
+ if (result == ERROR_FILE_NOT_FOUND)
+ attempt_count = 0;
+ else if (result != ERROR_SUCCESS)
+ return false;
+
+ ++attempt_count;
+ SetDWValue(key, blacklist::kBeaconAttemptCount, attempt_count);
+
+ if (attempt_count >= blacklist::kBeaconMaxAttempts) {
+ blacklist_state = blacklist::BLACKLIST_SETUP_FAILED;
+ SetDWValue(key, blacklist::kBeaconState, blacklist_state);
+ return false;
+ }
+ } else if (blacklist_state == blacklist::BLACKLIST_ENABLED) {
+ // If the blacklist succeeded on the previous run reset the failure
+ // counter.
+ result =
+ SetDWValue(key, blacklist::kBeaconAttemptCount, static_cast<DWORD>(0));
+ if (result != ERROR_SUCCESS) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+namespace blacklist {
+
+#if defined(_WIN64)
+ // Allocate storage for the pointer to the old NtMapViewOfSectionFunction.
+#pragma section(".oldntmap",write,read)
+ __declspec(allocate(".oldntmap"))
+ NtMapViewOfSectionFunction g_nt_map_view_of_section_func = NULL;
+#endif
+
+bool LeaveSetupBeacon() {
+ HKEY key = NULL;
+ DWORD disposition = 0;
+ LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
+ kRegistryBeaconPath,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_QUERY_VALUE | KEY_SET_VALUE,
+ NULL,
+ &key,
+ &disposition);
+ if (result != ERROR_SUCCESS)
+ return false;
+
+ // Retrieve the current blacklist state.
+ DWORD blacklist_state = BLACKLIST_STATE_MAX;
+ DWORD blacklist_state_size = sizeof(blacklist_state);
+ DWORD type = 0;
+ result = ::RegQueryValueEx(key,
+ kBeaconState,
+ 0,
+ &type,
+ reinterpret_cast<LPBYTE>(&blacklist_state),
+ &blacklist_state_size);
+
+ if (blacklist_state == BLACKLIST_DISABLED || result != ERROR_SUCCESS ||
+ type != REG_DWORD) {
+ ::RegCloseKey(key);
+ return false;
+ }
+
+ if (!GenerateStateFromBeaconAndAttemptCount(&key, blacklist_state)) {
+ ::RegCloseKey(key);
+ return false;
+ }
+
+ result = SetDWValue(&key, kBeaconState, BLACKLIST_SETUP_RUNNING);
+ ::RegCloseKey(key);
+
+ return (result == ERROR_SUCCESS);
+}
+
+bool ResetBeacon() {
+ HKEY key = NULL;
+ DWORD disposition = 0;
+ LONG result = ::RegCreateKeyEx(HKEY_CURRENT_USER,
+ kRegistryBeaconPath,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_QUERY_VALUE | KEY_SET_VALUE,
+ NULL,
+ &key,
+ &disposition);
+ if (result != ERROR_SUCCESS)
+ return false;
+
+ DWORD blacklist_state = BLACKLIST_STATE_MAX;
+ DWORD blacklist_state_size = sizeof(blacklist_state);
+ DWORD type = 0;
+ result = ::RegQueryValueEx(key,
+ kBeaconState,
+ 0,
+ &type,
+ reinterpret_cast<LPBYTE>(&blacklist_state),
+ &blacklist_state_size);
+
+ if (result != ERROR_SUCCESS || type != REG_DWORD) {
+ ::RegCloseKey(key);
+ return false;
+ }
+
+ // Reaching this point with the setup running state means the setup did not
+ // crash, so we reset to enabled. Any other state indicates that setup was
+ // skipped; in that case we leave the state alone for later recording.
+ if (blacklist_state == BLACKLIST_SETUP_RUNNING)
+ result = SetDWValue(&key, kBeaconState, BLACKLIST_ENABLED);
+
+ ::RegCloseKey(key);
+ return (result == ERROR_SUCCESS);
+}
+
+int BlacklistSize() {
+ int size = -1;
+ while (blacklist::g_troublesome_dlls[++size] != NULL) {}
+
+ return size;
+}
+
+bool IsBlacklistInitialized() {
+ return g_blacklist_initialized;
+}
+
+bool AddDllToBlacklist(const wchar_t* dll_name) {
+ int blacklist_size = BlacklistSize();
+ // We need to leave one space at the end for the null pointer.
+ if (blacklist_size + 1 >= kTroublesomeDllsMaxCount)
+ return false;
+ for (int i = 0; i < blacklist_size; ++i) {
+ if (!_wcsicmp(g_troublesome_dlls[i], dll_name))
+ return true;
+ }
+
+ // Copy string to blacklist.
+ wchar_t* str_buffer = new wchar_t[wcslen(dll_name) + 1];
+ wcscpy(str_buffer, dll_name);
+
+ g_troublesome_dlls[blacklist_size] = str_buffer;
+ g_blocked_dlls[blacklist_size] = false;
+ return true;
+}
+
+bool RemoveDllFromBlacklist(const wchar_t* dll_name) {
+ int blacklist_size = BlacklistSize();
+ for (int i = 0; i < blacklist_size; ++i) {
+ if (!_wcsicmp(g_troublesome_dlls[i], dll_name)) {
+ // Found the thing to remove. Delete it then replace it with the last
+ // element.
+ delete[] g_troublesome_dlls[i];
+ g_troublesome_dlls[i] = g_troublesome_dlls[blacklist_size - 1];
+ g_troublesome_dlls[blacklist_size - 1] = NULL;
+
+ // Also update the stats recording if we have blocked this dll or not.
+ if (g_blocked_dlls[i])
+ --g_num_blocked_dlls;
+ g_blocked_dlls[i] = g_blocked_dlls[blacklist_size - 1];
+ return true;
+ }
+ }
+ return false;
+}
+
+// TODO(csharp): Maybe store these values in the registry so we can
+// still report them if Chrome crashes early.
+void SuccessfullyBlocked(const wchar_t** blocked_dlls, int* size) {
+ if (size == NULL)
+ return;
+
+ // If the array isn't valid or big enough, just report the size it needs to
+ // be and return.
+ if (blocked_dlls == NULL && *size < g_num_blocked_dlls) {
+ *size = g_num_blocked_dlls;
+ return;
+ }
+
+ *size = g_num_blocked_dlls;
+
+ int strings_to_fill = 0;
+ for (int i = 0; strings_to_fill < g_num_blocked_dlls && g_troublesome_dlls[i];
+ ++i) {
+ if (g_blocked_dlls[i]) {
+ blocked_dlls[strings_to_fill] = g_troublesome_dlls[i];
+ ++strings_to_fill;
+ }
+ }
+}
+
+void BlockedDll(size_t blocked_index) {
+ assert(blocked_index < kTroublesomeDllsMaxCount);
+
+ if (!g_blocked_dlls[blocked_index] &&
+ blocked_index < kTroublesomeDllsMaxCount) {
+ ++g_num_blocked_dlls;
+ g_blocked_dlls[blocked_index] = true;
+ }
+}
+
+bool Initialize(bool force) {
+ // Check to see that we found the functions we need in ntdll.
+ if (!InitializeInterceptImports())
+ return false;
+
+ // Check to see if this is a non-browser process, abort if so.
+ if (IsNonBrowserProcess())
+ return false;
+
+ // Check to see if the blacklist beacon is still set to running (indicating a
+ // failure) or disabled, and abort if so.
+ if (!force && !LeaveSetupBeacon())
+ return false;
+
+ // It is possible for other dlls to have already patched code by now and
+ // attempting to patch their code might result in crashes.
+ const bool kRelaxed = false;
+
+ // Create a thunk via the appropriate ServiceResolver instance.
+ sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed);
+
+ // Don't try blacklisting on unsupported OS versions.
+ if (!thunk)
+ return false;
+
+ BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_thunk_storage);
+
+ // Mark the thunk storage as readable and writeable, since we
+ // ready to write to it.
+ DWORD old_protect = 0;
+ if (!VirtualProtect(&g_thunk_storage,
+ sizeof(g_thunk_storage),
+ PAGE_EXECUTE_READWRITE,
+ &old_protect)) {
+ return false;
+ }
+
+ thunk->AllowLocalPatches();
+
+ // We declare this early so it can be used in the 64-bit block below and
+ // still work on 32-bit build when referenced at the end of the function.
+ BOOL page_executable = false;
+
+ // Replace the default NtMapViewOfSection with our patched version.
+#if defined(_WIN64)
+ NTSTATUS ret = thunk->Setup(::GetModuleHandle(sandbox::kNtdllName),
+ reinterpret_cast<void*>(&__ImageBase),
+ "NtMapViewOfSection",
+ NULL,
+ &blacklist::BlNtMapViewOfSection64,
+ thunk_storage,
+ sizeof(sandbox::ThunkData),
+ NULL);
+
+ // Keep a pointer to the original code, we don't have enough space to
+ // add it directly to the call.
+ g_nt_map_view_of_section_func = reinterpret_cast<NtMapViewOfSectionFunction>(
+ thunk_storage);
+
+ // Ensure that the pointer to the old function can't be changed.
+ page_executable = VirtualProtect(&g_nt_map_view_of_section_func,
+ sizeof(g_nt_map_view_of_section_func),
+ PAGE_EXECUTE_READ,
+ &old_protect);
+#else
+ NTSTATUS ret = thunk->Setup(::GetModuleHandle(sandbox::kNtdllName),
+ reinterpret_cast<void*>(&__ImageBase),
+ "NtMapViewOfSection",
+ NULL,
+ &blacklist::BlNtMapViewOfSection,
+ thunk_storage,
+ sizeof(sandbox::ThunkData),
+ NULL);
+#endif
+ delete thunk;
+
+ // Record if we have initialized the blacklist.
+ g_blacklist_initialized = NT_SUCCESS(ret);
+
+ // Mark the thunk storage as executable and prevent any future writes to it.
+ page_executable = page_executable && VirtualProtect(&g_thunk_storage,
+ sizeof(g_thunk_storage),
+ PAGE_EXECUTE_READ,
+ &old_protect);
+
+ AddDllsFromRegistryToBlacklist();
+
+ return NT_SUCCESS(ret) && page_executable;
+}
+
+bool AddDllsFromRegistryToBlacklist() {
+ HKEY key = NULL;
+ LONG result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
+ kRegistryFinchListPath,
+ 0,
+ KEY_QUERY_VALUE | KEY_SET_VALUE,
+ &key);
+
+ if (result != ERROR_SUCCESS)
+ return false;
+
+ // We add dlls from the registry to the blacklist, and then clear registry.
+ DWORD value_len;
+ DWORD name_len = MAX_PATH;
+ std::vector<wchar_t> name_buffer(name_len);
+ for (int i = 0; result == ERROR_SUCCESS; ++i) {
+ name_len = MAX_PATH;
+ value_len = 0;
+ result = ::RegEnumValue(
+ key, i, &name_buffer[0], &name_len, NULL, NULL, NULL, &value_len);
+ name_len = name_len + 1;
+ value_len = value_len + 1;
+ std::vector<wchar_t> value_buffer(value_len);
+ result = ::RegEnumValue(key, i, &name_buffer[0], &name_len, NULL, NULL,
+ reinterpret_cast<BYTE*>(&value_buffer[0]),
+ &value_len);
+ value_buffer[value_len - 1] = L'\0';
+
+ if (result == ERROR_SUCCESS) {
+ AddDllToBlacklist(&value_buffer[0]);
+ }
+ }
+
+ // Delete the finch registry key to clear the values.
+ result = ::RegDeleteKey(key, L"");
+
+ ::RegCloseKey(key);
+ return result == ERROR_SUCCESS;
+}
+
+} // namespace blacklist
diff --git a/chromium/chrome_elf/blacklist/blacklist.h b/chromium/chrome_elf/blacklist/blacklist.h
new file mode 100644
index 00000000000..58cc16b3b8f
--- /dev/null
+++ b/chromium/chrome_elf/blacklist/blacklist.h
@@ -0,0 +1,78 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_BLACKLIST_BLACKLIST_H_
+#define CHROME_ELF_BLACKLIST_BLACKLIST_H_
+
+#if defined(_WIN64)
+#include "sandbox/win/src/sandbox_nt_types.h"
+#endif
+
+namespace blacklist {
+
+// Max size of the DLL blacklist.
+const size_t kTroublesomeDllsMaxCount = 64;
+
+// The DLL blacklist.
+extern const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount];
+
+#if defined(_WIN64)
+extern NtMapViewOfSectionFunction g_nt_map_view_of_section_func;
+#endif
+
+// Attempts to leave a beacon in the current user's registry hive. If the
+// blacklist beacon doesn't say it is enabled or there are any other errors when
+// creating the beacon, returns false. Otherwise returns true. The intent of the
+// beacon is to act as an extra failure mode protection whereby if Chrome
+// repeatedly fails to start during blacklist setup, it will skip blacklisting
+// on the subsequent run.
+bool LeaveSetupBeacon();
+
+// Looks for the setup running beacon that LeaveSetupBeacon() creates and resets
+// it to to show the setup was successful.
+// Returns true if the beacon was successfully set to BLACKLIST_ENABLED.
+bool ResetBeacon();
+
+// Return the size of the current blacklist.
+int BlacklistSize();
+
+// Returns if true if the blacklist has been initialized.
+extern "C" bool IsBlacklistInitialized();
+
+// Adds the given dll name to the blacklist. Returns true if the dll name is in
+// the blacklist when this returns, false on error. Note that this will copy
+// |dll_name| and will leak it on exit if the string is not subsequently removed
+// using RemoveDllFromBlacklist.
+// Exposed for testing only, this shouldn't be exported from chrome_elf.dll.
+extern "C" bool AddDllToBlacklist(const wchar_t* dll_name);
+
+// Removes the given dll name from the blacklist. Returns true if it was
+// removed, false on error.
+// Exposed for testing only, this shouldn't be exported from chrome_elf.dll.
+extern "C" bool RemoveDllFromBlacklist(const wchar_t* dll_name);
+
+// Returns a list of all the dlls that have been successfully blocked by the
+// blacklist via blocked_dlls, if there is enough space (according to |size|).
+// |size| will always be modified to be the number of dlls that were blocked.
+// The caller doesn't own the strings and isn't expected to free them. These
+// strings won't be hanging unless RemoveDllFromBlacklist is called, but it
+// is only exposed in tests (and should stay that way).
+extern "C" void SuccessfullyBlocked(const wchar_t** blocked_dlls, int* size);
+
+// Add the dlls, originally passed in through finch, from the registry to the
+// blacklist so that they will be blocked identically to those hard coded in.
+extern "C" bool AddDllsFromRegistryToBlacklist();
+
+// Record that the dll at the given index was blocked.
+void BlockedDll(size_t blocked_index);
+
+// Initializes the DLL blacklist in the current process. This should be called
+// before any undesirable DLLs might be loaded. If |force| is set to true, then
+// initialization will take place even if a beacon is present. This is useful
+// for tests.
+bool Initialize(bool force);
+
+} // namespace blacklist
+
+#endif // CHROME_ELF_BLACKLIST_BLACKLIST_H_
diff --git a/chromium/chrome_elf/blacklist/blacklist_interceptions.cc b/chromium/chrome_elf/blacklist/blacklist_interceptions.cc
new file mode 100644
index 00000000000..28eb692accc
--- /dev/null
+++ b/chromium/chrome_elf/blacklist/blacklist_interceptions.cc
@@ -0,0 +1,276 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of NtMapViewOfSection intercept for 32 bit builds.
+//
+// TODO(robertshield): Implement the 64 bit intercept.
+
+#include "chrome_elf/blacklist/blacklist_interceptions.h"
+
+#include <string>
+#include <vector>
+
+// Note that only #includes from base that are either header-only or built into
+// base_static (see base/base.gyp) are allowed here.
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/win/pe_image.h"
+#include "chrome_elf/blacklist/blacklist.h"
+#include "chrome_elf/breakpad.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace {
+
+NtQuerySectionFunction g_nt_query_section_func = NULL;
+NtQueryVirtualMemoryFunction g_nt_query_virtual_memory_func = NULL;
+NtUnmapViewOfSectionFunction g_nt_unmap_view_of_section_func = NULL;
+
+// TODO(robertshield): Merge with ntdll exports cache.
+FARPROC GetNtDllExportByName(const char* export_name) {
+ HMODULE ntdll = ::GetModuleHandle(sandbox::kNtdllName);
+ return ::GetProcAddress(ntdll, export_name);
+}
+
+int DllMatch(const base::string16& module_name) {
+ for (int i = 0; blacklist::g_troublesome_dlls[i] != NULL; ++i) {
+ if (_wcsicmp(module_name.c_str(), blacklist::g_troublesome_dlls[i]) == 0)
+ return i;
+ }
+ return -1;
+}
+
+// TODO(robertshield): Some of the helper functions below overlap somewhat with
+// code in sandbox_nt_util.cc. See if they can be unified.
+
+// Native reimplementation of PSAPIs GetMappedFileName.
+base::string16 GetBackingModuleFilePath(PVOID address) {
+ DCHECK_NT(g_nt_query_virtual_memory_func);
+
+ // We'll start with something close to max_path characters for the name.
+ ULONG buffer_bytes = MAX_PATH * 2;
+ std::vector<BYTE> buffer_data(buffer_bytes);
+
+ for (;;) {
+ MEMORY_SECTION_NAME* section_name =
+ reinterpret_cast<MEMORY_SECTION_NAME*>(&buffer_data[0]);
+
+ if (!section_name)
+ break;
+
+ ULONG returned_bytes;
+ NTSTATUS ret = g_nt_query_virtual_memory_func(
+ NtCurrentProcess, address, MemorySectionName, section_name,
+ buffer_bytes, &returned_bytes);
+
+ if (STATUS_BUFFER_OVERFLOW == ret) {
+ // Retry the call with the given buffer size.
+ buffer_bytes = returned_bytes + 1;
+ buffer_data.resize(buffer_bytes);
+ section_name = NULL;
+ continue;
+ }
+ if (!NT_SUCCESS(ret))
+ break;
+
+ UNICODE_STRING* section_string =
+ reinterpret_cast<UNICODE_STRING*>(section_name);
+ return base::string16(section_string->Buffer,
+ section_string->Length / sizeof(wchar_t));
+ }
+
+ return base::string16();
+}
+
+bool IsModuleValidImageSection(HANDLE section,
+ PVOID *base,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size) {
+ DCHECK_NT(g_nt_query_section_func);
+
+ if (!section || !base || !view_size || offset)
+ return false;
+
+ SECTION_BASIC_INFORMATION basic_info;
+ SIZE_T bytes_returned;
+ NTSTATUS ret = g_nt_query_section_func(section, SectionBasicInformation,
+ &basic_info, sizeof(basic_info),
+ &bytes_returned);
+
+ if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned)
+ return false;
+
+ if (!(basic_info.Attributes & SEC_IMAGE))
+ return false;
+
+ return true;
+}
+
+base::string16 ExtractLoadedModuleName(const base::string16& module_path) {
+ if (module_path.empty() || module_path[module_path.size() - 1] == L'\\')
+ return base::string16();
+
+ size_t sep = module_path.find_last_of(L'\\');
+ if (sep == base::string16::npos)
+ return module_path;
+ else
+ return module_path.substr(sep+1);
+}
+
+// Fills |out_name| with the image name from the given |pe| image and |flags|
+// with additional info about the image.
+void SafeGetImageInfo(const base::win::PEImage& pe,
+ std::string* out_name,
+ uint32* flags) {
+ out_name->clear();
+ out_name->reserve(MAX_PATH);
+ *flags = 0;
+ __try {
+ if (pe.VerifyMagic()) {
+ *flags |= sandbox::MODULE_IS_PE_IMAGE;
+
+ PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
+ if (exports) {
+ const char* image_name = reinterpret_cast<const char*>(
+ pe.RVAToAddr(exports->Name));
+ size_t i = 0;
+ for (; i < MAX_PATH && *image_name; ++i, ++image_name)
+ out_name->push_back(*image_name);
+ }
+
+ PIMAGE_NT_HEADERS headers = pe.GetNTHeaders();
+ if (headers) {
+ if (headers->OptionalHeader.AddressOfEntryPoint)
+ *flags |= sandbox::MODULE_HAS_ENTRY_POINT;
+ if (headers->OptionalHeader.SizeOfCode)
+ *flags |= sandbox::MODULE_HAS_CODE;
+ }
+ }
+ } __except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
+ GetExceptionCode() == EXCEPTION_GUARD_PAGE ||
+ GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR) ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+ out_name->clear();
+ }
+}
+
+base::string16 GetImageInfoFromLoadedModule(HMODULE module, uint32* flags) {
+ std::string out_name;
+ base::win::PEImage pe(module);
+ SafeGetImageInfo(pe, &out_name, flags);
+ return base::string16(out_name.begin(), out_name.end());
+}
+
+bool IsSameAsCurrentProcess(HANDLE process) {
+ return (NtCurrentProcess == process) ||
+ (::GetProcessId(process) == ::GetCurrentProcessId());
+}
+
+NTSTATUS BlNtMapViewOfSectionImpl(
+ NtMapViewOfSectionFunction orig_MapViewOfSection,
+ HANDLE section,
+ HANDLE process,
+ PVOID *base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect) {
+ NTSTATUS ret = orig_MapViewOfSection(section, process, base, zero_bits,
+ commit_size, offset, view_size, inherit,
+ allocation_type, protect);
+
+ if (!NT_SUCCESS(ret) || !IsSameAsCurrentProcess(process) ||
+ !IsModuleValidImageSection(section, base, offset, view_size)) {
+ return ret;
+ }
+
+ HMODULE module = reinterpret_cast<HMODULE>(*base);
+ if (module) {
+ UINT image_flags;
+
+ base::string16 module_name(GetImageInfoFromLoadedModule(
+ reinterpret_cast<HMODULE>(*base), &image_flags));
+ base::string16 file_name(GetBackingModuleFilePath(*base));
+
+ if (module_name.empty() && (image_flags & sandbox::MODULE_HAS_CODE)) {
+ // If the module has no exports we retrieve the module name from the
+ // full path of the mapped section.
+ module_name = ExtractLoadedModuleName(file_name);
+ }
+
+ if (!module_name.empty()) {
+ int blocked_index = DllMatch(module_name);
+ if (blocked_index != -1) {
+ DCHECK_NT(g_nt_unmap_view_of_section_func);
+ g_nt_unmap_view_of_section_func(process, *base);
+ ret = STATUS_UNSUCCESSFUL;
+
+ blacklist::BlockedDll(blocked_index);
+ }
+ }
+ }
+
+ return ret;
+}
+
+} // namespace
+
+namespace blacklist {
+
+bool InitializeInterceptImports() {
+ g_nt_query_section_func =
+ reinterpret_cast<NtQuerySectionFunction>(
+ GetNtDllExportByName("NtQuerySection"));
+ g_nt_query_virtual_memory_func =
+ reinterpret_cast<NtQueryVirtualMemoryFunction>(
+ GetNtDllExportByName("NtQueryVirtualMemory"));
+ g_nt_unmap_view_of_section_func =
+ reinterpret_cast<NtUnmapViewOfSectionFunction>(
+ GetNtDllExportByName("NtUnmapViewOfSection"));
+
+ return (g_nt_query_section_func && g_nt_query_virtual_memory_func &&
+ g_nt_unmap_view_of_section_func);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI BlNtMapViewOfSection(
+ NtMapViewOfSectionFunction orig_MapViewOfSection,
+ HANDLE section,
+ HANDLE process,
+ PVOID *base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect) {
+ NTSTATUS ret = STATUS_UNSUCCESSFUL;
+
+ __try {
+ ret = BlNtMapViewOfSectionImpl(orig_MapViewOfSection, section, process,
+ base, zero_bits, commit_size, offset,
+ view_size, inherit, allocation_type,
+ protect);
+ } __except(GenerateCrashDump(GetExceptionInformation())) {
+ }
+
+ return ret;
+}
+
+#if defined(_WIN64)
+NTSTATUS WINAPI BlNtMapViewOfSection64(
+ HANDLE section, HANDLE process, PVOID *base, ULONG_PTR zero_bits,
+ SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size,
+ SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect) {
+ return BlNtMapViewOfSection(g_nt_map_view_of_section_func, section, process,
+ base, zero_bits, commit_size, offset, view_size,
+ inherit, allocation_type, protect);
+}
+#endif
+} // namespace blacklist
diff --git a/chromium/chrome_elf/blacklist/blacklist_interceptions.h b/chromium/chrome_elf/blacklist/blacklist_interceptions.h
new file mode 100644
index 00000000000..2ee96b475f8
--- /dev/null
+++ b/chromium/chrome_elf/blacklist/blacklist_interceptions.h
@@ -0,0 +1,43 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_BLACKLIST_BLACKLIST_INTERCEPTIONS_H_
+#define CHROME_ELF_BLACKLIST_BLACKLIST_INTERCEPTIONS_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace blacklist {
+
+bool InitializeInterceptImports();
+
+// Interception of NtMapViewOfSection within the current process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+SANDBOX_INTERCEPT NTSTATUS WINAPI BlNtMapViewOfSection(
+ NtMapViewOfSectionFunction orig_MapViewOfSection,
+ HANDLE section,
+ HANDLE process,
+ PVOID *base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect);
+
+#if defined(_WIN64)
+// Interception of NtMapViewOfSection within the current process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+SANDBOX_INTERCEPT NTSTATUS WINAPI BlNtMapViewOfSection64(
+ HANDLE section, HANDLE process, PVOID *base, ULONG_PTR zero_bits,
+ SIZE_T commit_size, PLARGE_INTEGER offset, PSIZE_T view_size,
+ SECTION_INHERIT inherit, ULONG allocation_type, ULONG protect);
+#endif
+
+} // namespace blacklist
+
+#endif // CHROME_ELF_BLACKLIST_BLACKLIST_INTERCEPTIONS_H_
diff --git a/chromium/chrome_elf/breakpad.cc b/chromium/chrome_elf/breakpad.cc
new file mode 100644
index 00000000000..4c20324b208
--- /dev/null
+++ b/chromium/chrome_elf/breakpad.cc
@@ -0,0 +1,178 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module contains the necessary code to register the Breakpad exception
+// handler. This implementation is based on Chrome's crash reporting code.
+
+#include "chrome_elf/breakpad.h"
+
+#include <sddl.h>
+
+#include "base/macros.h"
+#include "breakpad/src/client/windows/handler/exception_handler.h"
+#include "chrome_elf/chrome_elf_util.h"
+#include "version.h" // NOLINT
+
+google_breakpad::ExceptionHandler* g_elf_breakpad = NULL;
+
+namespace {
+
+const wchar_t kBreakpadProductName[] = L"Chrome";
+const wchar_t kBreakpadVersionEntry[] = L"ver";
+const wchar_t kBreakpadProdEntry[] = L"prod";
+const wchar_t kBreakpadPlatformEntry[] = L"plat";
+const wchar_t kBreakpadPlatformWin32[] = L"Win32";
+
+// The protocol for connecting to the out-of-process Breakpad crash
+// reporter is different for x86-32 and x86-64: the message sizes
+// are different because the message struct contains a pointer. As
+// a result, there are two different named pipes to connect to. The
+// 64-bit one is distinguished with an "-x64" suffix.
+const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices\\";
+const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
+const wchar_t kSystemPrincipalSid[] = L"S-1-5-18";
+
+const wchar_t kNoErrorDialogs[] = L"noerrdialogs";
+const wchar_t kChromeHeadless[] = L"CHROME_HEADLESS";
+
+google_breakpad::CustomClientInfo* GetCustomInfo() {
+ static google_breakpad::CustomInfoEntry ver_entry(
+ kBreakpadVersionEntry, TEXT(CHROME_VERSION_STRING));
+ static google_breakpad::CustomInfoEntry prod_entry(
+ kBreakpadProdEntry, kBreakpadProductName);
+ static google_breakpad::CustomInfoEntry plat_entry(
+ kBreakpadPlatformEntry, kBreakpadPlatformWin32);
+ static google_breakpad::CustomInfoEntry entries[] = {
+ ver_entry, prod_entry, plat_entry };
+ static google_breakpad::CustomClientInfo custom_info = {
+ entries, arraysize(entries) };
+ return &custom_info;
+}
+
+base::string16 GetUserSidString() {
+ // Get the current token.
+ HANDLE token = NULL;
+ base::string16 user_sid;
+ if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+ return user_sid;
+
+ DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+ BYTE user_bytes[sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE] = {};
+ TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes);
+
+ wchar_t* sid_string = NULL;
+ if (::GetTokenInformation(token, TokenUser, user, size, &size) &&
+ user->User.Sid &&
+ ::ConvertSidToStringSid(user->User.Sid, &sid_string)) {
+ user_sid = sid_string;
+ ::LocalFree(sid_string);
+ }
+
+ CloseHandle(token);
+ return user_sid;
+}
+
+bool IsHeadless() {
+ DWORD ret = ::GetEnvironmentVariable(L"CHROME_HEADLESS", NULL, 0);
+ if (ret != 0)
+ return true;
+
+ wchar_t* command_line = ::GetCommandLine();
+
+ // Note: Since this is a pure substring search rather than a check for a
+ // switch, there is a small chance that this code will match things that the
+ // Chrome code (which executes a similar check) does not. However, as long as
+ // no other switches contain the string "noerrdialogs", it should not be an
+ // issue.
+ return (command_line && wcsstr(command_line, kNoErrorDialogs));
+}
+
+} // namespace
+
+int GenerateCrashDump(EXCEPTION_POINTERS* exinfo) {
+ DWORD code = exinfo->ExceptionRecord->ExceptionCode;
+ if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ if (g_elf_breakpad != NULL)
+ g_elf_breakpad->WriteMinidumpForException(exinfo);
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+void InitializeCrashReporting() {
+ wchar_t exe_path[MAX_PATH] = {};
+ if (!::GetModuleFileName(NULL, exe_path, arraysize(exe_path)))
+ return;
+
+ // Disable the message box for assertions.
+ _CrtSetReportMode(_CRT_ASSERT, 0);
+
+ // Get the alternate dump directory. We use the temp path.
+ // N.B. We don't use base::GetTempDir() here to avoid running more code then
+ // necessary before crashes can be properly reported.
+ wchar_t temp_directory[MAX_PATH + 1] = {};
+ DWORD length = GetTempPath(MAX_PATH, temp_directory);
+ if (length == 0)
+ return;
+
+ // Minidump with stacks, PEB, TEBs and unloaded module list.
+ MINIDUMP_TYPE dump_type = static_cast<MINIDUMP_TYPE>(
+ MiniDumpWithProcessThreadData | // Get PEB and TEB.
+ MiniDumpWithUnloadedModules | // Get unloaded modules when available.
+ MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by
+ // stack.
+
+#if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
+ bool is_official_chrome_build = true;
+#else
+ bool is_official_chrome_build = false;
+#endif
+
+ base::string16 pipe_name;
+
+ bool enabled_by_policy = false;
+ bool use_policy = ReportingIsEnforcedByPolicy(&enabled_by_policy);
+
+ if (!use_policy && IsHeadless()) {
+ pipe_name = kChromePipeName;
+ } else if (use_policy ?
+ enabled_by_policy :
+ (is_official_chrome_build && AreUsageStatsEnabled(exe_path))) {
+ // Build the pipe name. It can be one of:
+ // 32-bit system: \\.\pipe\GoogleCrashServices\S-1-5-18
+ // 32-bit user: \\.\pipe\GoogleCrashServices\<user SID>
+ // 64-bit system: \\.\pipe\GoogleCrashServices\S-1-5-18-x64
+ // 64-bit user: \\.\pipe\GoogleCrashServices\<user SID>-x64
+ base::string16 user_sid = IsSystemInstall(exe_path) ? kSystemPrincipalSid :
+ GetUserSidString();
+ if (user_sid.empty())
+ return;
+
+ pipe_name = kGoogleUpdatePipeName;
+ pipe_name += user_sid;
+
+#if defined(_WIN64)
+ pipe_name += L"-x64";
+#endif
+ } else {
+ // Either this is a Chromium build, reporting is disabled by policy or the
+ // user has not given consent.
+ return;
+ }
+
+ g_elf_breakpad = new google_breakpad::ExceptionHandler(
+ temp_directory,
+ NULL,
+ NULL,
+ NULL,
+ google_breakpad::ExceptionHandler::HANDLER_ALL,
+ dump_type,
+ pipe_name.c_str(),
+ GetCustomInfo());
+
+ if (g_elf_breakpad->IsOutOfProcess()) {
+ // Tells breakpad to handle breakpoint and single step exceptions.
+ g_elf_breakpad->set_handle_debug_exceptions(true);
+ }
+}
diff --git a/chromium/chrome_elf/breakpad.h b/chromium/chrome_elf/breakpad.h
new file mode 100644
index 00000000000..8067708b647
--- /dev/null
+++ b/chromium/chrome_elf/breakpad.h
@@ -0,0 +1,34 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_BREAKPAD_H_
+#define CHROME_ELF_BREAKPAD_H_
+
+#include <windows.h>
+
+namespace google_breakpad {
+class ExceptionHandler;
+}
+
+// Initializes collection and upload of crash reports. This will only be done if
+// the user has agreed to crash dump reporting.
+//
+// Crash reporting has to be initialized as early as possible (e.g., the first
+// thing in main()) to catch crashes occuring during process startup.
+// Crashes which occur during the global static construction phase will not
+// be caught and reported. This should not be a problem as static non-POD
+// objects are not allowed by the style guide and exceptions to this rule are
+// rare.
+void InitializeCrashReporting();
+
+// Generates a crashdump for the provided |exinfo|. This crashdump will be
+// either be saved locally, or uploaded, depending on how the ExceptionHandler
+// has been configured.
+int GenerateCrashDump(EXCEPTION_POINTERS* exinfo);
+
+// Global pointer to the ExceptionHandler. This is initialized by
+// InitializeCrashReporting() and used by GenerateCrashDump() to record dumps.
+extern google_breakpad::ExceptionHandler* g_elf_breakpad;
+
+#endif // CHROME_ELF_BREAKPAD_H_
diff --git a/chromium/chrome_elf/chrome_elf.def b/chromium/chrome_elf/chrome_elf.def
index d3ca82f80d2..566a8fb0657 100644
--- a/chromium/chrome_elf/chrome_elf.def
+++ b/chromium/chrome_elf/chrome_elf.def
@@ -5,4 +5,8 @@
LIBRARY "chrome_elf.dll"
EXPORTS
- InitChromeElf
+ CreateFileW=CreateFileWRedirect
+ GetRedirectCount
+ IsBlacklistInitialized
+ SignalChromeElf
+ SuccessfullyBlocked
diff --git a/chromium/chrome_elf/chrome_elf.gyp b/chromium/chrome_elf/chrome_elf.gyp
index cf0a0e95d68..0b612a87c6e 100644
--- a/chromium/chrome_elf/chrome_elf.gyp
+++ b/chromium/chrome_elf/chrome_elf.gyp
@@ -6,11 +6,38 @@
'chromium_code': 1,
},
'includes': [
+ '../build/util/version.gypi',
'../build/win_precompile.gypi',
- '../chrome/version.gypi',
+ 'blacklist.gypi',
+ 'dll_hash.gypi',
],
'targets': [
{
+ 'target_name': 'chrome_elf_resources',
+ 'type': 'none',
+ 'conditions': [
+ ['branding == "Chrome"', {
+ 'variables': {
+ 'branding_path': '../chrome/app/theme/google_chrome/BRANDING',
+ },
+ }, { # else branding!="Chrome"
+ 'variables': {
+ 'branding_path': '../chrome/app/theme/chromium/BRANDING',
+ },
+ }],
+ ],
+ 'variables': {
+ 'output_dir': 'chrome_elf',
+ 'template_input_path': '../chrome/app/chrome_version.rc.version',
+ },
+ 'sources': [
+ 'chrome_elf.ver',
+ ],
+ 'includes': [
+ '../chrome/version_resource_rules.gypi',
+ ],
+ },
+ {
'target_name': 'chrome_elf',
'type': 'shared_library',
'include_dirs': [
@@ -20,31 +47,72 @@
'chrome_elf.def',
'chrome_elf_main.cc',
'chrome_elf_main.h',
+ '<(SHARED_INTERMEDIATE_DIR)/chrome_elf/chrome_elf_version.rc',
],
'dependencies': [
+ 'blacklist',
+ 'chrome_elf_breakpad',
'chrome_elf_lib',
+ 'chrome_elf_resources',
],
'msvs_settings': {
'VCLinkerTool': {
- 'BaseAddress': '0x01c20000',
- # Set /SUBSYSTEM:WINDOWS for chrome_elf.dll (for consistency).
+ 'conditions': [
+ ['target_arch=="ia32"', {
+ # Don't set an x64 base address (to avoid breaking HE-ASLR).
+ 'BaseAddress': '0x01c20000',
+ }],
+ ],
+ # Set /SUBSYSTEM:WINDOWS.
'SubSystem': '2',
+ 'AdditionalDependencies!': [
+ 'user32.lib',
+ ],
+ 'IgnoreDefaultLibraryNames': [
+ 'user32.lib',
+ ],
},
},
},
{
- 'target_name': 'chrome_elf_unittests',
+ 'target_name': 'chrome_elf_unittests_exe',
+ 'product_name': 'chrome_elf_unittests',
'type': 'executable',
'sources': [
+ 'blacklist/test/blacklist_test.cc',
+ 'chrome_elf_util_unittest.cc',
+ 'create_file/chrome_create_file_unittest.cc',
+ 'elf_imports_unittest.cc',
'ntdll_cache_unittest.cc',
],
'include_dirs': [
'..',
+ '<(SHARED_INTERMEDIATE_DIR)',
],
'dependencies': [
'chrome_elf_lib',
- '<(DEPTH)/base/base.gyp:run_all_unittests',
- '<(DEPTH)/testing/gtest.gyp:gtest',
+ '../base/base.gyp:base',
+ '../base/base.gyp:run_all_unittests',
+ '../base/base.gyp:test_support_base',
+ '../sandbox/sandbox.gyp:sandbox',
+ '../testing/gtest.gyp:gtest',
+ 'blacklist',
+ 'blacklist_test_dll_1',
+ 'blacklist_test_dll_2',
+ 'blacklist_test_dll_3',
+ 'blacklist_test_main_dll',
+ ],
+ },
+ {
+ # A dummy target to ensure that chrome_elf.dll and chrome.exe gets built
+ # when building chrome_elf_unittests.exe without introducing an
+ # explicit runtime dependency.
+ 'target_name': 'chrome_elf_unittests',
+ 'type': 'none',
+ 'dependencies': [
+ '../chrome/chrome.gyp:chrome',
+ 'chrome_elf',
+ 'chrome_elf_unittests_exe',
],
},
{
@@ -54,10 +122,94 @@
'..',
],
'sources': [
- 'chrome_elf_types.h',
+ 'create_file/chrome_create_file.cc',
+ 'create_file/chrome_create_file.h',
'ntdll_cache.cc',
'ntdll_cache.h',
],
+ 'dependencies': [
+ 'chrome_elf_common',
+ '../base/base.gyp:base_static',
+ '../sandbox/sandbox.gyp:sandbox',
+ ],
+ },
+ {
+ 'target_name': 'chrome_elf_constants',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'chrome_elf_constants.cc',
+ 'chrome_elf_constants.h',
+ ],
},
+ {
+ 'target_name': 'chrome_elf_common',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'chrome_elf_constants',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'chrome_elf_types.h',
+ 'chrome_elf_util.cc',
+ 'chrome_elf_util.h',
+ 'thunk_getter.cc',
+ 'thunk_getter.h',
+ ],
+ },
+ {
+ 'target_name': 'chrome_elf_breakpad',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '..',
+ '<(SHARED_INTERMEDIATE_DIR)',
+ ],
+ 'sources': [
+ 'breakpad.cc',
+ 'breakpad.h',
+ ],
+ 'dependencies': [
+ 'chrome_elf_common',
+ '../breakpad/breakpad.gyp:breakpad_handler',
+ '../chrome/chrome.gyp:chrome_version_header',
+ ],
+ },
+ ], # targets
+ 'conditions': [
+ ['component=="shared_library"', {
+ 'targets': [
+ {
+ 'target_name': 'chrome_redirects',
+ 'type': 'shared_library',
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'chrome_redirects.def',
+ 'chrome_redirects_main.cc',
+ ],
+ 'dependencies': [
+ 'chrome_elf_lib',
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'conditions': [
+ ['target_arch=="ia32"', {
+ # Don't set an x64 base address (to avoid breaking HE-ASLR).
+ 'BaseAddress': '0x01c20000',
+ }],
+ ],
+ # Set /SUBSYSTEM:WINDOWS.
+ 'SubSystem': '2',
+ },
+ },
+ },
+ ],
+ }],
],
}
+
diff --git a/chromium/chrome_elf/chrome_elf.ver b/chromium/chrome_elf/chrome_elf.ver
new file mode 100644
index 00000000000..78f890e7ece
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf.ver
@@ -0,0 +1,2 @@
+INTERNAL_NAME=chrome_elf_dll
+ORIGINAL_FILENAME=chrome_elf.dll
diff --git a/chromium/chrome_elf/chrome_elf_constants.cc b/chromium/chrome_elf/chrome_elf_constants.cc
new file mode 100644
index 00000000000..a7ee1c929c2
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_constants.cc
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_elf/chrome_elf_constants.h"
+
+#if defined(GOOGLE_CHROME_BUILD)
+const wchar_t kAppDataDirName[] = L"Google\\Chrome";
+#else
+const wchar_t kAppDataDirName[] = L"Chromium";
+#endif
+const wchar_t kCanaryAppDataDirName[] = L"Google\\Chrome SxS";
+const wchar_t kLocalStateFilename[] = L"Local State";
+const wchar_t kPreferencesFilename[] = L"Preferences";
+const wchar_t kUserDataDirName[] = L"User Data";
+
+namespace blacklist {
+
+const wchar_t kRegistryBeaconPath[] = L"SOFTWARE\\Google\\Chrome\\BLBeacon";
+const wchar_t kRegistryFinchListPath[] =
+ L"SOFTWARE\\Google\\Chrome\\BLFinchList";
+const wchar_t kBeaconVersion[] = L"version";
+const wchar_t kBeaconState[] = L"state";
+const wchar_t kBeaconAttemptCount[] = L"failed_count";
+
+const DWORD kBeaconMaxAttempts = 2;
+
+} // namespace blacklist
diff --git a/chromium/chrome_elf/chrome_elf_constants.h b/chromium/chrome_elf/chrome_elf_constants.h
new file mode 100644
index 00000000000..92e44cad7c4
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_constants.h
@@ -0,0 +1,51 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A handful of resource-like constants related to the ChromeELF.
+
+#ifndef CHROME_ELF_CHROME_ELF_CONSTANTS_H_
+#define CHROME_ELF_CHROME_ELF_CONSTANTS_H_
+
+#include <windows.h>
+
+// directory names
+extern const wchar_t kAppDataDirName[];
+extern const wchar_t kCanaryAppDataDirName[];
+extern const wchar_t kLocalStateFilename[];
+extern const wchar_t kPreferencesFilename[];
+extern const wchar_t kUserDataDirName[];
+
+namespace blacklist {
+
+// The registry path of the blacklist beacon.
+extern const wchar_t kRegistryBeaconPath[];
+
+// The registry path of the finch blacklist dlls.
+extern const wchar_t kRegistryFinchListPath[];
+
+// The properties for the blacklist beacon.
+extern const wchar_t kBeaconVersion[];
+extern const wchar_t kBeaconState[];
+extern const wchar_t kBeaconAttemptCount[];
+
+// The number of failures that can occur on startup with the beacon enabled
+// before we give up and turn off the blacklist.
+extern const DWORD kBeaconMaxAttempts;
+
+// The states for the blacklist setup code.
+enum BlacklistState {
+ BLACKLIST_DISABLED = 0,
+ BLACKLIST_ENABLED,
+ // The blacklist setup code is running. If this is the state at startup, it
+ // means the last setup crashed.
+ BLACKLIST_SETUP_RUNNING,
+ // If the last setup crashed, we reassign the state to failed.
+ BLACKLIST_SETUP_FAILED,
+ // Always keep this at the end.
+ BLACKLIST_STATE_MAX,
+};
+
+} // namespace blacklist
+
+#endif // CHROME_ELF_CHROME_ELF_CONSTANTS_H_
diff --git a/chromium/chrome_elf/chrome_elf_main.cc b/chromium/chrome_elf/chrome_elf_main.cc
index 42914309704..989493a122e 100644
--- a/chromium/chrome_elf/chrome_elf_main.cc
+++ b/chromium/chrome_elf/chrome_elf_main.cc
@@ -6,15 +6,24 @@
#include "chrome_elf/chrome_elf_main.h"
+#include "chrome_elf/blacklist/blacklist.h"
+#include "chrome_elf/breakpad.h"
#include "chrome_elf/ntdll_cache.h"
-void InitChromeElf() {
- // This method is a no-op which may be called to force a load-time dependency
- // on chrome_elf.dll.
+void SignalChromeElf() {
+ blacklist::ResetBeacon();
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
- if (reason == DLL_PROCESS_ATTACH)
- InitCache();
+ if (reason == DLL_PROCESS_ATTACH) {
+ InitializeCrashReporting();
+
+ __try {
+ InitCache();
+ blacklist::Initialize(false); // Don't force, abort if beacon is present.
+ } __except(GenerateCrashDump(GetExceptionInformation())) {
+ }
+ }
+
return TRUE;
}
diff --git a/chromium/chrome_elf/chrome_elf_main.h b/chromium/chrome_elf/chrome_elf_main.h
index 7d02ddd9912..52bf067a579 100644
--- a/chromium/chrome_elf/chrome_elf_main.h
+++ b/chromium/chrome_elf/chrome_elf_main.h
@@ -5,6 +5,6 @@
#ifndef CHROME_ELF_CHROME_ELF_MAIN_H_
#define CHROME_ELF_CHROME_ELF_MAIN_H_
-extern "C" void InitChromeElf();
+extern "C" void SignalChromeElf();
#endif // CHROME_ELF_CHROME_ELF_MAIN_H_
diff --git a/chromium/chrome_elf/chrome_elf_util.cc b/chromium/chrome_elf/chrome_elf_util.cc
new file mode 100644
index 00000000000..a547d0bda04
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_util.cc
@@ -0,0 +1,209 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_elf/chrome_elf_util.h"
+
+#include <windows.h>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+namespace {
+
+const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState";
+const wchar_t kRegPathClientStateMedium[] =
+ L"Software\\Google\\Update\\ClientStateMedium";
+#if defined(GOOGLE_CHROME_BUILD)
+const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Google\\Chrome";
+#else
+const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Chromium";
+#endif // defined(GOOGLE_CHROME_BUILD)
+
+const wchar_t kRegValueUsageStats[] = L"usagestats";
+const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
+const wchar_t kMetricsReportingEnabled[] =L"MetricsReportingEnabled";
+
+const wchar_t kAppGuidCanary[] =
+ L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
+const wchar_t kAppGuidGoogleChrome[] =
+ L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
+const wchar_t kAppGuidGoogleBinaries[] =
+ L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
+
+bool ReadKeyValueString(bool system_install, const wchar_t* key_path,
+ const wchar_t* guid, const wchar_t* value_to_read,
+ base::string16* value_out) {
+ HKEY key = NULL;
+ value_out->clear();
+
+ base::string16 full_key_path(key_path);
+ full_key_path.append(1, L'\\');
+ full_key_path.append(guid);
+
+ if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+ full_key_path.c_str(), 0,
+ KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) !=
+ ERROR_SUCCESS) {
+ return false;
+ }
+
+ const size_t kMaxStringLength = 1024;
+ wchar_t raw_value[kMaxStringLength] = {};
+ DWORD size = sizeof(raw_value);
+ DWORD type = REG_SZ;
+ LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type,
+ reinterpret_cast<LPBYTE>(raw_value), &size);
+
+ if (result == ERROR_SUCCESS) {
+ if (type != REG_SZ || (size & 1) != 0) {
+ result = ERROR_NOT_SUPPORTED;
+ } else if (size == 0) {
+ *raw_value = L'\0';
+ } else if (raw_value[size / sizeof(wchar_t) - 1] != L'\0') {
+ if ((size / sizeof(wchar_t)) < kMaxStringLength)
+ raw_value[size / sizeof(wchar_t)] = L'\0';
+ else
+ result = ERROR_MORE_DATA;
+ }
+ }
+
+ if (result == ERROR_SUCCESS)
+ *value_out = raw_value;
+
+ ::RegCloseKey(key);
+
+ return result == ERROR_SUCCESS;
+}
+
+bool ReadKeyValueDW(bool system_install, const wchar_t* key_path,
+ base::string16 guid, const wchar_t* value_to_read,
+ DWORD* value_out) {
+ HKEY key = NULL;
+ *value_out = 0;
+
+ base::string16 full_key_path(key_path);
+ full_key_path.append(1, L'\\');
+ full_key_path.append(guid);
+
+ if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+ full_key_path.c_str(), 0,
+ KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) !=
+ ERROR_SUCCESS) {
+ return false;
+ }
+
+ DWORD size = sizeof(*value_out);
+ DWORD type = REG_DWORD;
+ LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type,
+ reinterpret_cast<BYTE*>(value_out), &size);
+
+ ::RegCloseKey(key);
+
+ return result == ERROR_SUCCESS && size == sizeof(*value_out);
+}
+
+} // namespace
+
+bool IsCanary(const wchar_t* exe_path) {
+ return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL;
+}
+
+bool IsSystemInstall(const wchar_t* exe_path) {
+ wchar_t program_dir[MAX_PATH] = {};
+ DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir,
+ arraysize(program_dir));
+ if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret))
+ return true;
+
+ ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir,
+ arraysize(program_dir));
+ if (ret && ret < MAX_PATH && !wcsncmp(exe_path, program_dir, ret))
+ return true;
+
+ return false;
+}
+
+bool IsMultiInstall(bool is_system_install) {
+ base::string16 args;
+ if (!ReadKeyValueString(is_system_install, kRegPathClientState,
+ kAppGuidGoogleChrome, kUninstallArgumentsField,
+ &args)) {
+ return false;
+ }
+ return args.find(L"--multi-install") != base::string16::npos;
+}
+
+bool AreUsageStatsEnabled(const wchar_t* exe_path) {
+ bool enabled = true;
+ bool controlled_by_policy = ReportingIsEnforcedByPolicy(&enabled);
+
+ if (controlled_by_policy && !enabled)
+ return false;
+
+ bool system_install = IsSystemInstall(exe_path);
+ base::string16 app_guid;
+
+ if (IsCanary(exe_path)) {
+ app_guid = kAppGuidCanary;
+ } else {
+ app_guid = IsMultiInstall(system_install) ? kAppGuidGoogleBinaries :
+ kAppGuidGoogleChrome;
+ }
+
+ DWORD out_value = 0;
+ if (system_install &&
+ ReadKeyValueDW(system_install, kRegPathClientStateMedium, app_guid,
+ kRegValueUsageStats, &out_value)) {
+ return out_value == 1;
+ }
+
+ return ReadKeyValueDW(system_install, kRegPathClientState, app_guid,
+ kRegValueUsageStats, &out_value) && out_value == 1;
+}
+
+bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
+ HKEY key = NULL;
+ DWORD value = 0;
+ BYTE* value_bytes = reinterpret_cast<BYTE*>(&value);
+ DWORD size = sizeof(value);
+ DWORD type = REG_DWORD;
+
+ if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, kRegPathChromePolicy, 0,
+ KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
+ if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type,
+ value_bytes, &size) == ERROR_SUCCESS) {
+ *breakpad_enabled = value != 0;
+ }
+ ::RegCloseKey(key);
+ return size == sizeof(value);
+ }
+
+ if (::RegOpenKeyEx(HKEY_CURRENT_USER, kRegPathChromePolicy, 0,
+ KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
+ if (::RegQueryValueEx(key, kMetricsReportingEnabled, 0, &type,
+ value_bytes, &size) == ERROR_SUCCESS) {
+ *breakpad_enabled = value != 0;
+ }
+ ::RegCloseKey(key);
+ return size == sizeof(value);
+ }
+
+ return false;
+}
+
+bool IsNonBrowserProcess() {
+ typedef bool (*IsSandboxedProcessFunc)();
+ IsSandboxedProcessFunc is_sandboxed_process_func =
+ reinterpret_cast<IsSandboxedProcessFunc>(
+ GetProcAddress(GetModuleHandle(NULL), "IsSandboxedProcess"));
+ bool is_sandboxed_process =
+ is_sandboxed_process_func && is_sandboxed_process_func();
+
+ // TODO(robertshield): Drop the command line check when we drop support for
+ // enabling chrome_elf in unsandboxed processes.
+ wchar_t* command_line = GetCommandLine();
+ bool has_process_type_flag = command_line && wcsstr(command_line, L"--type");
+
+ return (has_process_type_flag || is_sandboxed_process);
+}
diff --git a/chromium/chrome_elf/chrome_elf_util.h b/chromium/chrome_elf/chrome_elf_util.h
new file mode 100644
index 00000000000..e87dc7fab70
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_util.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_CHROME_ELF_UTIL_H_
+#define CHROME_ELF_CHROME_ELF_UTIL_H_
+
+#include "base/strings/string16.h"
+
+// Returns true if |exe_path| points to a Chrome installed in an SxS
+// installation.
+bool IsCanary(const wchar_t* exe_path);
+
+// Returns true if |exe_path| points to a per-user level Chrome installation.
+bool IsSystemInstall(const wchar_t* exe_path);
+
+// Returns true if current installation of Chrome is a multi-install.
+bool IsMultiInstall(bool is_system_install);
+
+// Returns true if usage stats collecting is enabled for this user.
+bool AreUsageStatsEnabled(const wchar_t* exe_path);
+
+// Returns true if a policy is in effect. |breakpad_enabled| will be set to true
+// if stats collecting is permitted by this policy and false if not.
+bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled);
+
+// Returns true if invoked in a Chrome process other than the main browser
+// process. False otherwise.
+bool IsNonBrowserProcess();
+
+#endif // CHROME_ELF_CHROME_ELF_UTIL_H_
diff --git a/chromium/chrome_elf/chrome_elf_util_unittest.cc b/chromium/chrome_elf/chrome_elf_util_unittest.cc
new file mode 100644
index 00000000000..1cb6488ecaa
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_util_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_elf/chrome_elf_util.h"
+
+#include <tuple>
+
+#include "base/test/test_reg_util_win.h"
+#include "base/win/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState";
+const wchar_t kRegPathClientStateMedium[] =
+ L"Software\\Google\\Update\\ClientStateMedium";
+const wchar_t kRegValueUsageStats[] = L"usagestats";
+const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
+
+const wchar_t kAppGuidCanary[] =
+ L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
+const wchar_t kAppGuidGoogleChrome[] =
+ L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
+const wchar_t kAppGuidGoogleBinaries[] =
+ L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
+
+const wchar_t kCanaryExePath[] =
+ L"C:\\Users\\user\\AppData\\Local\\Google\\Chrome SxS\\Application"
+ L"\\chrome.exe";
+const wchar_t kChromeSystemExePath[] =
+ L"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
+const wchar_t kChromeUserExePath[] =
+ L"C:\\Users\\user\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe";
+const wchar_t kChromiumExePath[] =
+ L"C:\\Users\\user\\AppData\\Local\\Chromium\\Application\\chrome.exe";
+
+
+TEST(ChromeElfUtilTest, CanaryTest) {
+ EXPECT_TRUE(IsCanary(kCanaryExePath));
+ EXPECT_FALSE(IsCanary(kChromeUserExePath));
+ EXPECT_FALSE(IsCanary(kChromiumExePath));
+}
+
+TEST(ChromeElfUtilTest, SystemInstallTest) {
+ EXPECT_TRUE(IsSystemInstall(kChromeSystemExePath));
+ EXPECT_FALSE(IsSystemInstall(kChromeUserExePath));
+}
+
+// Parameterized test with paramters:
+// 1: product: "canary" or "google"
+// 2: install level: "user" or "system"
+// 3: install mode: "single" or "multi"
+class ChromeElfUtilTest :
+ public testing::TestWithParam<std::tuple<const char*,
+ const char*,
+ const char*> > {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE,
+ L"chrome_elf_test_local");
+ override_manager_.OverrideRegistry(HKEY_CURRENT_USER,
+ L"chrome_elf_test_current");
+ const char* app;
+ const char* level;
+ const char* mode;
+ std::tie(app, level, mode) = GetParam();
+ is_canary_ = (std::string(app) == "canary");
+ system_level_ = (std::string(level) != "user");
+ multi_install_ = (std::string(mode) != "single");
+ if (is_canary_) {
+ ASSERT_FALSE(system_level_);
+ ASSERT_FALSE(multi_install_);
+ app_guid_ = kAppGuidCanary;
+ chrome_path_ = kCanaryExePath;
+ } else {
+ app_guid_ = kAppGuidGoogleChrome;
+ chrome_path_ = (system_level_ ? kChromeSystemExePath :
+ kChromeUserExePath);
+ }
+ if (multi_install_) {
+ SetMultiInstallStateInRegistry(system_level_, true);
+ app_guid_ = kAppGuidGoogleBinaries;
+ }
+ }
+
+ base::string16 BuildKey(const wchar_t* path, const wchar_t* guid) {
+ base::string16 full_key_path(path);
+ full_key_path.append(1, L'\\');
+ full_key_path.append(guid);
+ return full_key_path;
+ }
+
+ void SetUsageStat(DWORD value, bool state_medium) {
+ LONG result = base::win::RegKey(
+ system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+ BuildKey(state_medium ? kRegPathClientStateMedium : kRegPathClientState,
+ app_guid_).c_str(),
+ KEY_SET_VALUE).WriteValue(kRegValueUsageStats, value);
+ ASSERT_EQ(ERROR_SUCCESS, result);
+ }
+
+ void SetMultiInstallStateInRegistry(bool system_install, bool multi) {
+ base::win::RegKey key(
+ system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+ BuildKey(kRegPathClientState, kAppGuidGoogleChrome).c_str(),
+ KEY_SET_VALUE);
+ LONG result;
+ if (multi) {
+ result = key.WriteValue(kUninstallArgumentsField,
+ L"yadda yadda --multi-install yadda yadda");
+ } else {
+ result = key.DeleteValue(kUninstallArgumentsField);
+ }
+ ASSERT_EQ(ERROR_SUCCESS, result);
+ }
+
+ const wchar_t* app_guid_;
+ const wchar_t* chrome_path_;
+ bool system_level_;
+ bool multi_install_;
+ bool is_canary_;
+ registry_util::RegistryOverrideManager override_manager_;
+};
+
+TEST_P(ChromeElfUtilTest, MultiInstallTest) {
+ if (is_canary_)
+ return;
+ SetMultiInstallStateInRegistry(system_level_, true);
+ EXPECT_TRUE(IsMultiInstall(system_level_));
+
+ SetMultiInstallStateInRegistry(system_level_, false);
+ EXPECT_FALSE(IsMultiInstall(system_level_));
+}
+
+TEST_P(ChromeElfUtilTest, UsageStatsAbsent) {
+ EXPECT_FALSE(AreUsageStatsEnabled(chrome_path_));
+}
+
+TEST_P(ChromeElfUtilTest, UsageStatsZero) {
+ SetUsageStat(0, false);
+ EXPECT_FALSE(AreUsageStatsEnabled(chrome_path_));
+}
+
+TEST_P(ChromeElfUtilTest, UsageStatsOne) {
+ SetUsageStat(1, false);
+ EXPECT_TRUE(AreUsageStatsEnabled(chrome_path_));
+ if (is_canary_) {
+ EXPECT_FALSE(AreUsageStatsEnabled(kChromeUserExePath));
+ EXPECT_FALSE(AreUsageStatsEnabled(kChromeSystemExePath));
+ } else if (system_level_) {
+ EXPECT_FALSE(AreUsageStatsEnabled(kCanaryExePath));
+ EXPECT_FALSE(AreUsageStatsEnabled(kChromeUserExePath));
+ } else {
+ EXPECT_FALSE(AreUsageStatsEnabled(kCanaryExePath));
+ EXPECT_FALSE(AreUsageStatsEnabled(kChromeSystemExePath));
+ }
+}
+
+TEST_P(ChromeElfUtilTest, UsageStatsZeroInStateMedium) {
+ if (!system_level_)
+ return;
+ SetUsageStat(0, true);
+ EXPECT_FALSE(AreUsageStatsEnabled(chrome_path_));
+}
+
+TEST_P(ChromeElfUtilTest, UsageStatsOneInStateMedium) {
+ if (!system_level_)
+ return;
+ SetUsageStat(1, true);
+ EXPECT_TRUE(AreUsageStatsEnabled(chrome_path_));
+ EXPECT_FALSE(AreUsageStatsEnabled(kCanaryExePath));
+ EXPECT_FALSE(AreUsageStatsEnabled(kChromeUserExePath));
+}
+
+INSTANTIATE_TEST_CASE_P(Canary, ChromeElfUtilTest,
+ testing::Combine(testing::Values("canary"),
+ testing::Values("user"),
+ testing::Values("single")));
+INSTANTIATE_TEST_CASE_P(GoogleChrome, ChromeElfUtilTest,
+ testing::Combine(testing::Values("google"),
+ testing::Values("user", "system"),
+ testing::Values("single", "multi")));
+
+} // namespace
diff --git a/chromium/chrome_elf/chrome_exe_manifest.template b/chromium/chrome_elf/chrome_exe_manifest.template
deleted file mode 100644
index 7c66328e206..00000000000
--- a/chromium/chrome_elf/chrome_exe_manifest.template
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type='win32'
- name='@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
- version='@MAJOR@.@MINOR@.@BUILD@.@PATCH@' language='*'/>
- </dependentAssembly>
- </dependency>
-</assembly> \ No newline at end of file
diff --git a/chromium/chrome_elf/chrome_exe_manifest_action.gypi b/chromium/chrome_elf/chrome_exe_manifest_action.gypi
deleted file mode 100644
index 89453dbc952..00000000000
--- a/chromium/chrome_elf/chrome_exe_manifest_action.gypi
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This file contains an action which can be used to construct a manifest file
-# declaring a dependency on chrome_elf.dll. This manifest can then be merged
-# into the manifest of the executable and embedded into it when it is built.
-
-# To use this the following variables need to be defined:
-# version_path: string: path to file containing version data (e.g.
-# chrome/VERSION).
-# version_py_path: string: path to file containing version script (e.g.
-# chrome/tools/build/version.py).
-
-{
- 'variables': {
- 'template_input_path':
- '<(DEPTH)/chrome_elf/chrome_exe_manifest.template',
- },
- 'inputs': [
- '<(template_input_path)',
- '<(version_path)',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/chrome_elf/version_assembly.manifest',
- ],
- 'action': [
- 'python', '<(version_py_path)',
- '-f', '<(version_path)',
- '<(template_input_path)',
- '<@(_outputs)',
- ],
- 'message': 'Generating <@(_outputs)',
-} \ No newline at end of file
diff --git a/chromium/chrome_elf/chrome_redirects.def b/chromium/chrome_elf/chrome_redirects.def
new file mode 100644
index 00000000000..1238dc6c4cf
--- /dev/null
+++ b/chromium/chrome_elf/chrome_redirects.def
@@ -0,0 +1,9 @@
+; Copyright 2014 The Chromium Authors. All rights reserved.
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+LIBRARY "chrome_redirects.dll"
+
+EXPORTS
+ CreateFileW=CreateFileWRedirect
+ GetRedirectCount
diff --git a/chromium/chrome_elf/chrome_redirects_main.cc b/chromium/chrome_elf/chrome_redirects_main.cc
new file mode 100644
index 00000000000..960d07c8806
--- /dev/null
+++ b/chromium/chrome_elf/chrome_redirects_main.cc
@@ -0,0 +1,14 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "chrome_elf/ntdll_cache.h"
+
+BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
+ if (reason == DLL_PROCESS_ATTACH)
+ InitCache();
+
+ return TRUE;
+}
diff --git a/chromium/chrome_elf/create_file/chrome_create_file.cc b/chromium/chrome_elf/create_file/chrome_create_file.cc
new file mode 100644
index 00000000000..2db6f8d8372
--- /dev/null
+++ b/chromium/chrome_elf/create_file/chrome_create_file.cc
@@ -0,0 +1,330 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_elf/create_file/chrome_create_file.h"
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "chrome_elf/chrome_elf_constants.h"
+#include "chrome_elf/chrome_elf_util.h"
+#include "chrome_elf/ntdll_cache.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/nt_internals.h"
+
+namespace {
+
+// From ShlObj.h in the Windows SDK.
+#define CSIDL_LOCAL_APPDATA 0x001c
+
+typedef BOOL (WINAPI *PathIsUNCFunction)(
+ IN LPCWSTR path);
+
+typedef BOOL (WINAPI *PathAppendFunction)(
+ IN LPWSTR path,
+ IN LPCWSTR more);
+
+typedef BOOL (WINAPI *PathIsPrefixFunction)(
+ IN LPCWSTR prefix,
+ IN LPCWSTR path);
+
+typedef LPCWSTR (WINAPI *PathFindFileName)(
+ IN LPCWSTR path);
+
+typedef HRESULT (WINAPI *SHGetFolderPathFunction)(
+ IN HWND hwnd_owner,
+ IN int folder,
+ IN HANDLE token,
+ IN DWORD flags,
+ OUT LPWSTR path);
+
+PathIsUNCFunction g_path_is_unc_func;
+PathAppendFunction g_path_append_func;
+PathIsPrefixFunction g_path_is_prefix_func;
+PathFindFileName g_path_find_filename_func;
+SHGetFolderPathFunction g_get_folder_func;
+
+// Record the number of calls we've redirected so far.
+int g_redirect_count = 0;
+
+// Populates the g_*_func pointers to functions which will be used in
+// ShouldBypass(). Chrome_elf cannot have a load-time dependency on shell32 or
+// shlwapi as this would induce a load-time dependency on user32.dll. Instead,
+// the addresses of the functions we need are retrieved the first time this
+// method is called, and cached to avoid subsequent calls to GetProcAddress().
+// It is assumed that the host process will never unload these functions.
+// Returns true if all the functions needed are present.
+bool PopulateShellFunctions() {
+ // Early exit if functions have already been populated.
+ if (g_path_is_unc_func && g_path_append_func &&
+ g_path_is_prefix_func && g_get_folder_func) {
+ return true;
+ }
+
+ // Get the addresses of the functions we need and store them for future use.
+ // These handles are intentionally leaked to ensure that these modules do not
+ // get unloaded.
+ HMODULE shell32 = ::LoadLibrary(L"shell32.dll");
+ HMODULE shlwapi = ::LoadLibrary(L"shlwapi.dll");
+
+ if (!shlwapi || !shell32)
+ return false;
+
+ g_path_is_unc_func = reinterpret_cast<PathIsUNCFunction>(
+ ::GetProcAddress(shlwapi, "PathIsUNCW"));
+ g_path_append_func = reinterpret_cast<PathAppendFunction>(
+ ::GetProcAddress(shlwapi, "PathAppendW"));
+ g_path_is_prefix_func = reinterpret_cast<PathIsPrefixFunction>(
+ ::GetProcAddress(shlwapi, "PathIsPrefixW"));
+ g_path_find_filename_func = reinterpret_cast<PathFindFileName>(
+ ::GetProcAddress(shlwapi, "PathFindFileNameW"));
+ g_get_folder_func = reinterpret_cast<SHGetFolderPathFunction>(
+ ::GetProcAddress(shell32, "SHGetFolderPathW"));
+
+ return g_path_is_unc_func && g_path_append_func && g_path_is_prefix_func &&
+ g_path_find_filename_func && g_get_folder_func;
+}
+
+} // namespace
+
+// Turn off optimization to make sure these calls don't get inlined.
+#pragma optimize("", off)
+// Wrapper method for kernel32!CreateFile, to avoid setting off caller
+// mitigation detectors.
+HANDLE CreateFileWImpl(LPCWSTR file_name,
+ DWORD desired_access,
+ DWORD share_mode,
+ LPSECURITY_ATTRIBUTES security_attributes,
+ DWORD creation_disposition,
+ DWORD flags_and_attributes,
+ HANDLE template_file) {
+ return CreateFile(file_name,
+ desired_access,
+ share_mode,
+ security_attributes,
+ creation_disposition,
+ flags_and_attributes,
+ template_file);
+
+}
+
+HANDLE WINAPI CreateFileWRedirect(
+ LPCWSTR file_name,
+ DWORD desired_access,
+ DWORD share_mode,
+ LPSECURITY_ATTRIBUTES security_attributes,
+ DWORD creation_disposition,
+ DWORD flags_and_attributes,
+ HANDLE template_file) {
+ if (ShouldBypass(file_name)) {
+ ++g_redirect_count;
+ return CreateFileNTDLL(file_name,
+ desired_access,
+ share_mode,
+ security_attributes,
+ creation_disposition,
+ flags_and_attributes,
+ template_file);
+ }
+ return CreateFileWImpl(file_name,
+ desired_access,
+ share_mode,
+ security_attributes,
+ creation_disposition,
+ flags_and_attributes,
+ template_file);
+}
+#pragma optimize("", on)
+
+int GetRedirectCount() {
+ return g_redirect_count;
+}
+
+HANDLE CreateFileNTDLL(
+ LPCWSTR file_name,
+ DWORD desired_access,
+ DWORD share_mode,
+ LPSECURITY_ATTRIBUTES security_attributes,
+ DWORD creation_disposition,
+ DWORD flags_and_attributes,
+ HANDLE template_file) {
+ HANDLE file_handle = INVALID_HANDLE_VALUE;
+ NTSTATUS result = STATUS_UNSUCCESSFUL;
+ IO_STATUS_BLOCK io_status_block = {};
+ ULONG flags = 0;
+
+ // Convert from Win32 domain to to NT creation disposition values.
+ switch (creation_disposition) {
+ case CREATE_NEW:
+ creation_disposition = FILE_CREATE;
+ break;
+ case CREATE_ALWAYS:
+ creation_disposition = FILE_OVERWRITE_IF;
+ break;
+ case OPEN_EXISTING:
+ creation_disposition = FILE_OPEN;
+ break;
+ case OPEN_ALWAYS:
+ creation_disposition = FILE_OPEN_IF;
+ break;
+ case TRUNCATE_EXISTING:
+ creation_disposition = FILE_OVERWRITE;
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ // Translate the flags that need no validation:
+ if (!(flags_and_attributes & FILE_FLAG_OVERLAPPED))
+ flags |= FILE_SYNCHRONOUS_IO_NONALERT;
+
+ if (flags_and_attributes & FILE_FLAG_WRITE_THROUGH)
+ flags |= FILE_WRITE_THROUGH;
+
+ if (flags_and_attributes & FILE_FLAG_RANDOM_ACCESS)
+ flags |= FILE_RANDOM_ACCESS;
+
+ if (flags_and_attributes & FILE_FLAG_SEQUENTIAL_SCAN)
+ flags |= FILE_SEQUENTIAL_ONLY;
+
+ if (flags_and_attributes & FILE_FLAG_DELETE_ON_CLOSE) {
+ flags |= FILE_DELETE_ON_CLOSE;
+ desired_access |= DELETE;
+ }
+
+ if (flags_and_attributes & FILE_FLAG_BACKUP_SEMANTICS)
+ flags |= FILE_OPEN_FOR_BACKUP_INTENT;
+ else
+ flags |= FILE_NON_DIRECTORY_FILE;
+
+
+ if (flags_and_attributes & FILE_FLAG_OPEN_REPARSE_POINT)
+ flags |= FILE_OPEN_REPARSE_POINT;
+
+ if (flags_and_attributes & FILE_FLAG_OPEN_NO_RECALL)
+ flags |= FILE_OPEN_NO_RECALL;
+
+ if (!g_ntdll_lookup["RtlInitUnicodeString"])
+ return INVALID_HANDLE_VALUE;
+
+ NtCreateFileFunction create_file;
+ char thunk_buffer[sizeof(sandbox::ThunkData)] = {};
+
+ if (g_nt_thunk_storage.data[0] != 0) {
+ create_file = reinterpret_cast<NtCreateFileFunction>(&g_nt_thunk_storage);
+ // Copy the thunk data to a buffer on the stack for debugging purposes.
+ memcpy(&thunk_buffer, &g_nt_thunk_storage, sizeof(sandbox::ThunkData));
+ } else if (g_ntdll_lookup["NtCreateFile"]) {
+ create_file =
+ reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
+ } else {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ RtlInitUnicodeStringFunction init_unicode_string =
+ reinterpret_cast<RtlInitUnicodeStringFunction>(
+ g_ntdll_lookup["RtlInitUnicodeString"]);
+
+ UNICODE_STRING path_unicode_string;
+
+ // Format the path into an NT path. Arguably this should be done with
+ // RtlDosPathNameToNtPathName_U, but afaict this is equivalent for
+ // local paths. Using this with a UNC path name will almost certainly
+ // break in interesting ways.
+ base::string16 filename_string(L"\\??\\");
+ filename_string += file_name;
+
+ init_unicode_string(&path_unicode_string, filename_string.c_str());
+
+ OBJECT_ATTRIBUTES path_attributes = {};
+ InitializeObjectAttributes(&path_attributes,
+ &path_unicode_string,
+ OBJ_CASE_INSENSITIVE,
+ NULL, // No Root Directory
+ NULL); // No Security Descriptor
+
+ // Set desired_access, and flags_and_attributes to match those
+ // set by kernel32!CreateFile.
+ desired_access |= 0x100080;
+ flags_and_attributes &= 0x2FFA7;
+
+ result = create_file(&file_handle,
+ desired_access,
+ &path_attributes,
+ &io_status_block,
+ 0, // Allocation size
+ flags_and_attributes,
+ share_mode,
+ creation_disposition,
+ flags,
+ NULL,
+ 0);
+
+ if (result != STATUS_SUCCESS) {
+ if (result == STATUS_OBJECT_NAME_COLLISION &&
+ creation_disposition == FILE_CREATE) {
+ SetLastError(ERROR_FILE_EXISTS);
+ }
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (creation_disposition == FILE_OPEN_IF) {
+ SetLastError(io_status_block.Information == FILE_OPENED ?
+ ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
+ } else if (creation_disposition == FILE_OVERWRITE_IF) {
+ SetLastError(io_status_block.Information == FILE_OVERWRITTEN ?
+ ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
+ } else {
+ SetLastError(ERROR_SUCCESS);
+ }
+
+ return file_handle;
+}
+
+bool ShouldBypass(LPCWSTR file_path) {
+ // Do not redirect in non-browser processes.
+ if (IsNonBrowserProcess())
+ return false;
+
+ // If the shell functions are not present, forward the call to kernel32.
+ if (!PopulateShellFunctions())
+ return false;
+
+ // Forward all UNC filepaths to kernel32.
+ if (g_path_is_unc_func(file_path))
+ return false;
+
+ wchar_t local_appdata_path[MAX_PATH];
+
+ // Get the %LOCALAPPDATA% Path and append the location of our UserData
+ // directory to it.
+ HRESULT appdata_result = g_get_folder_func(
+ NULL, CSIDL_LOCAL_APPDATA, NULL, 0, local_appdata_path);
+
+ wchar_t buffer[MAX_PATH] = {};
+ if (!GetModuleFileNameW(NULL, buffer, MAX_PATH))
+ return false;
+
+ bool is_canary = IsCanary(buffer);
+
+ // If getting the %LOCALAPPDATA% path or appending to it failed, then forward
+ // the call to kernel32.
+ if (!SUCCEEDED(appdata_result) ||
+ !g_path_append_func(local_appdata_path, is_canary ?
+ kCanaryAppDataDirName : kAppDataDirName) ||
+ !g_path_append_func(local_appdata_path, kUserDataDirName)) {
+ return false;
+ }
+
+ LPCWSTR file_name = g_path_find_filename_func(file_path);
+
+ bool in_userdata_dir = !!g_path_is_prefix_func(local_appdata_path, file_path);
+ bool is_settings_file = wcscmp(file_name, kPreferencesFilename) == 0 ||
+ wcscmp(file_name, kLocalStateFilename) == 0;
+
+ // Check if we are trying to access the Preferences in the UserData dir. If
+ // so, then redirect the call to bypass kernel32.
+ return in_userdata_dir && is_settings_file;
+}
diff --git a/chromium/chrome_elf/create_file/chrome_create_file.h b/chromium/chrome_elf/create_file/chrome_create_file.h
new file mode 100644
index 00000000000..f9f15c35634
--- /dev/null
+++ b/chromium/chrome_elf/create_file/chrome_create_file.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_CREATE_FILE_CHROME_CREATE_FILE_H_
+#define CHROME_ELF_CREATE_FILE_CHROME_CREATE_FILE_H_
+
+#include <windows.h>
+
+#include "chrome_elf/chrome_elf_types.h"
+
+// A CreateFileW replacement that will call NTCreateFile directly when the
+// criteria defined in ShouldBypass() are satisfied for |lp_file_name|.
+extern "C" HANDLE WINAPI CreateFileWRedirect(
+ LPCWSTR file_name,
+ DWORD desired_access,
+ DWORD share_mode,
+ LPSECURITY_ATTRIBUTES security_attributes,
+ DWORD creation_disposition,
+ DWORD flags_and_attributes,
+ HANDLE template_file);
+
+// Returns the count of CreateFile calls redirected so far.
+extern "C" int GetRedirectCount();
+
+// Partial reimplementation of kernel32!CreateFile (very partial: only handles
+// reading and writing to files in the User Data directory).
+HANDLE CreateFileNTDLL(
+ LPCWSTR file_name,
+ DWORD desired_access,
+ DWORD share_mode,
+ LPSECURITY_ATTRIBUTES security_attributes,
+ DWORD creation_disposition,
+ DWORD flags_and_attributes,
+ HANDLE template_file);
+
+// Determines whether or not we should use our version of CreateFile, or the
+// system version (only uses ours if we're writing to the user data directory).
+bool ShouldBypass(LPCWSTR file_name);
+
+#endif // CHROME_ELF_CREATE_FILE_CHROME_CREATE_FILE_H_
diff --git a/chromium/chrome_elf/create_file/chrome_create_file_unittest.cc b/chromium/chrome_elf/create_file/chrome_create_file_unittest.cc
new file mode 100644
index 00000000000..5b776073681
--- /dev/null
+++ b/chromium/chrome_elf/create_file/chrome_create_file_unittest.cc
@@ -0,0 +1,408 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_elf/create_file/chrome_create_file.h"
+
+#include <windows.h>
+
+#include <bitset>
+#include <string>
+
+#include "base/base_paths_win.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/iat_patch_function.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "chrome_elf/chrome_elf_constants.h"
+#include "chrome_elf/ntdll_cache.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+
+namespace {
+
+// Test fixtures -------------------------------------------------------------
+
+class ChromeCreateFileTest : public PlatformTest {
+ protected:
+ struct NtCreateFileParams {
+ ACCESS_MASK desired_access;
+ OBJECT_ATTRIBUTES object_attributes;
+ PLARGE_INTEGER allocation_size;
+ ULONG file_attributes;
+ ULONG share_access;
+ ULONG create_disposition;
+ ULONG create_options;
+ PVOID ea_buffer;
+ ULONG ea_length;
+ };
+
+ enum CallPath {
+ ELF,
+ KERNEL
+ };
+
+ template<CallPath path>
+ static NTSTATUS WINAPI FakeNtCreateFile(
+ PHANDLE file_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status_block,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG share_access,
+ ULONG create_disposition,
+ ULONG create_options,
+ PVOID ea_buffer,
+ ULONG ea_length) {
+ return self_->HandleCreateFileCall(file_handle,
+ desired_access,
+ object_attributes,
+ io_status_block,
+ allocation_size,
+ file_attributes,
+ share_access,
+ create_disposition,
+ create_options,
+ ea_buffer,
+ ea_length,
+ path);
+ }
+
+ virtual void SetUp() OVERRIDE {
+ original_thread_ = base::PlatformThread::CurrentId();
+ InitCache();
+ PlatformTest::SetUp();
+
+ base::FilePath user_data_dir;
+ PathService::Get(base::DIR_LOCAL_APP_DATA, &user_data_dir);
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(user_data_dir));
+ ASSERT_TRUE(temp_dir2_.CreateUniqueTempDir());
+ self_ = this;
+ }
+
+ void UnsetThunkStorage() {
+ DWORD old_protect = 0;
+ EXPECT_TRUE(::VirtualProtect(&g_nt_thunk_storage,
+ sizeof(g_nt_thunk_storage),
+ PAGE_EXECUTE_READWRITE,
+ &old_protect));
+ memset(&g_nt_thunk_storage, 0, sizeof(g_nt_thunk_storage));
+
+ EXPECT_TRUE(::VirtualProtect(&g_nt_thunk_storage,
+ sizeof(g_nt_thunk_storage),
+ PAGE_EXECUTE_READ,
+ &old_protect));
+ }
+
+ void RedirectNtCreateFileCalls() {
+ UnsetThunkStorage();
+ old_func_ptr_ =
+ reinterpret_cast<NtCreateFileFunction>(g_ntdll_lookup["NtCreateFile"]);
+
+ // KernelBase.dll only exists for Win7 and later, prior to that, kernel32
+ // imports from ntdll directly.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7) {
+ patcher_.Patch(L"kernel32.dll", "ntdll.dll", "NtCreateFile",
+ reinterpret_cast<void(*)()>(&FakeNtCreateFile<KERNEL>));
+ } else {
+ patcher_.Patch(L"kernelbase.dll", "ntdll.dll", "NtCreateFile",
+ reinterpret_cast<void(*)()>(&FakeNtCreateFile<KERNEL>));
+ }
+
+ g_ntdll_lookup["NtCreateFile"] = reinterpret_cast<void(*)()>(
+ &ChromeCreateFileTest::FakeNtCreateFile<ELF>);
+ }
+
+ void ResetNtCreateFileCalls() {
+ g_ntdll_lookup["NtCreateFile"] = reinterpret_cast<void*>(old_func_ptr_);
+ patcher_.Unpatch();
+ }
+
+ NTSTATUS HandleCreateFileCall(PHANDLE file_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status_block,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG share_access,
+ ULONG create_disposition,
+ ULONG create_options,
+ PVOID ea_buffer,
+ ULONG ea_length,
+ CallPath call_path) {
+ if (original_thread_ == base::PlatformThread::CurrentId()) {
+ SetParams(desired_access,
+ object_attributes,
+ allocation_size,
+ file_attributes,
+ share_access,
+ create_disposition,
+ create_options,
+ ea_buffer,
+ ea_length,
+ call_path == ELF ? &elf_params_ : &kernel_params_);
+ }
+
+ // Forward the call to the real NTCreateFile.
+ return old_func_ptr_(file_handle,
+ desired_access,
+ object_attributes,
+ io_status_block,
+ allocation_size,
+ file_attributes,
+ share_access,
+ create_disposition,
+ create_options,
+ ea_buffer,
+ ea_length);
+ }
+
+ void SetParams(ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG share_access,
+ ULONG create_disposition,
+ ULONG create_options,
+ PVOID ea_buffer,
+ ULONG ea_length,
+ NtCreateFileParams* params) {
+ params->desired_access = desired_access;
+ params->object_attributes.Length = object_attributes->Length;
+ params->object_attributes.ObjectName = object_attributes->ObjectName;
+ params->object_attributes.RootDirectory = object_attributes->RootDirectory;
+ params->object_attributes.Attributes = object_attributes->Attributes;
+ params->object_attributes.SecurityDescriptor =
+ object_attributes->SecurityDescriptor;
+ params->object_attributes.SecurityQualityOfService =
+ object_attributes->SecurityQualityOfService;
+ params->allocation_size = allocation_size;
+ params->file_attributes = file_attributes;
+ params->share_access = share_access;
+ params->create_disposition = create_disposition;
+ params->create_options = create_options;
+ params->ea_buffer = ea_buffer;
+ params->ea_length = ea_length;
+ }
+
+ void CheckParams() {
+ std::bitset<32> elf((int) elf_params_.desired_access);
+ std::bitset<32> ker((int) kernel_params_.desired_access);
+
+ EXPECT_EQ(kernel_params_.desired_access, elf_params_.desired_access)
+ << elf << "\n" << ker;
+ EXPECT_EQ(kernel_params_.object_attributes.Length,
+ elf_params_.object_attributes.Length);
+ EXPECT_EQ(kernel_params_.object_attributes.RootDirectory,
+ elf_params_.object_attributes.RootDirectory);
+ EXPECT_EQ(kernel_params_.object_attributes.Attributes,
+ elf_params_.object_attributes.Attributes);
+ EXPECT_EQ(kernel_params_.object_attributes.SecurityDescriptor,
+ elf_params_.object_attributes.SecurityDescriptor);
+ EXPECT_EQ(kernel_params_.allocation_size, elf_params_.allocation_size);
+ EXPECT_EQ(kernel_params_.file_attributes, elf_params_.file_attributes);
+ EXPECT_EQ(kernel_params_.share_access, elf_params_.share_access);
+ EXPECT_EQ(kernel_params_.create_disposition,
+ elf_params_.create_disposition);
+ EXPECT_EQ(kernel_params_.create_options, elf_params_.create_options);
+ EXPECT_EQ(kernel_params_.ea_buffer, elf_params_.ea_buffer);
+ EXPECT_EQ(kernel_params_.ea_length, elf_params_.ea_length);
+ }
+
+ void DoWriteCheck(const base::FilePath& path, DWORD flag, bool is_system) {
+ base::win::ScopedHandle file_handle;
+ const char kTestData[] = "0123456789";
+ int buffer_size = sizeof(kTestData) - 1;
+ DWORD bytes_written;
+
+ if (is_system) {
+ file_handle.Set(::CreateFileW(path.value().c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | flag,
+ NULL));
+ } else {
+ file_handle.Set(CreateFileNTDLL(path.value().c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | flag,
+ NULL));
+ }
+
+
+ EXPECT_FALSE(file_handle == INVALID_HANDLE_VALUE);
+ ::WriteFile(file_handle, kTestData, buffer_size, &bytes_written, NULL);
+ EXPECT_EQ(buffer_size, bytes_written);
+ }
+
+ void DoReadCheck(const base::FilePath& path, DWORD flag, bool is_system) {
+ base::win::ScopedHandle file_handle;
+ const char kTestData[] = "0123456789";
+ int buffer_size = sizeof(kTestData) - 1;
+ DWORD bytes_read;
+ char read_buffer[10];
+
+ if (is_system) {
+ file_handle.Set(::CreateFileW(path.value().c_str(),
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | flag,
+ NULL));
+ } else {
+ file_handle.Set(CreateFileNTDLL(path.value().c_str(),
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | flag,
+ NULL));
+ }
+
+ EXPECT_FALSE(file_handle == INVALID_HANDLE_VALUE);
+ ::ReadFile(file_handle, read_buffer, buffer_size, &bytes_read, NULL);
+ EXPECT_EQ(buffer_size, bytes_read);
+ EXPECT_EQ(0, memcmp(kTestData, read_buffer, bytes_read));
+ }
+
+ void RunChecks(DWORD flag, bool check_reads) {
+ // Make sure we can write to this file handle when called via the system.
+ base::FilePath junk_path_1 = temp_dir_.path().Append(L"junk_1.txt");
+ base::FilePath junk_path_2 = temp_dir_.path().Append(L"junk_2.txt");
+ DoWriteCheck(junk_path_1, flag, true);
+ DoWriteCheck(junk_path_2, flag, false);
+ CheckParams();
+
+ if (check_reads) {
+ // Make sure we can read from this file handle when called via the system.
+ DoReadCheck(junk_path_1, flag, true);
+ DoReadCheck(junk_path_2, flag, false);
+ CheckParams();
+ }
+ base::DeleteFile(junk_path_1, false);
+ base::DeleteFile(junk_path_2, false);
+
+ }
+
+ static ChromeCreateFileTest* self_;
+
+ NtCreateFileFunction old_func_ptr_;
+ base::ScopedTempDir temp_dir_;
+ base::ScopedTempDir temp_dir2_;
+ base::win::IATPatchFunction patcher_;
+ NtCreateFileParams kernel_params_;
+ NtCreateFileParams elf_params_;
+ base::PlatformThreadId original_thread_;
+};
+
+ChromeCreateFileTest* ChromeCreateFileTest::self_ = NULL;
+
+// Tests ---------------------------------------------------------------------
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_ATTRIBUTE_NORMAL) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_ATTRIBUTE_NORMAL, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_WRITE_THROUGH) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_WRITE_THROUGH, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_RANDOM_ACCESS) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_RANDOM_ACCESS, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_SEQUENTIAL_SCAN) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_SEQUENTIAL_SCAN, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_DELETE_ON_CLOSE) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_DELETE_ON_CLOSE, false);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_BACKUP_SEMANTICS) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_BACKUP_SEMANTICS, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_OPEN_REPARSE_POINT) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_OPEN_REPARSE_POINT, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, CheckParams_FILE_FLAG_OPEN_NO_RECALL) {
+ RedirectNtCreateFileCalls();
+ RunChecks(FILE_FLAG_OPEN_NO_RECALL, true);
+ ResetNtCreateFileCalls();
+}
+
+TEST_F(ChromeCreateFileTest, BypassTest) {
+ std::wstring UNC_filepath_file(L"\\\\.\\some_file.txt");
+
+ base::FilePath local_path;
+ PathService::Get(base::DIR_LOCAL_APP_DATA, &local_path);
+
+ base::FilePath local_prefs_path = local_path.Append(kAppDataDirName).Append(
+ kUserDataDirName).Append(L"default\\Preferences");
+ base::FilePath local_state_path = local_path.Append(kAppDataDirName).Append(
+ kUserDataDirName).Append(L"ninja\\Local State");
+ base::FilePath local_junk_path = local_path.Append(kAppDataDirName).Append(
+ kUserDataDirName).Append(L"default\\Junk");
+
+ base::FilePath desktop_path;
+ PathService::Get(base::DIR_USER_DESKTOP, &desktop_path);
+ base::FilePath desktop_junk_path =
+ desktop_path.Append(L"Downloads\\junk.txt");
+ base::FilePath desktop_prefs_path =
+ desktop_path.Append(L"Downloads\\Preferences");
+
+ // Don't redirect UNC files.
+ EXPECT_FALSE(ShouldBypass(UNC_filepath_file.c_str()));
+
+ // Don't redirect if file is not in UserData directory.
+ EXPECT_FALSE(ShouldBypass(desktop_junk_path.value().c_str()));
+ EXPECT_FALSE(ShouldBypass(desktop_prefs_path.value().c_str()));
+
+ // Only redirect "Preferences" and "Local State" files.
+ EXPECT_TRUE(ShouldBypass(local_prefs_path.value().c_str()));
+ EXPECT_TRUE(ShouldBypass(local_state_path.value().c_str()));
+ EXPECT_FALSE(ShouldBypass(local_junk_path.value().c_str()));
+}
+
+TEST_F(ChromeCreateFileTest, ReadWriteFromNtDll) {
+ UnsetThunkStorage();
+ base::FilePath file_name = temp_dir_.path().Append(L"some_file.txt");
+ DoWriteCheck(file_name, FILE_ATTRIBUTE_NORMAL, false);
+ DoReadCheck(file_name, FILE_ATTRIBUTE_NORMAL, false);
+}
+
+TEST_F(ChromeCreateFileTest, ReadWriteFromThunk) {
+ base::FilePath file_name = temp_dir_.path().Append(L"some_file.txt");
+ DoWriteCheck(file_name, FILE_ATTRIBUTE_NORMAL, false);
+ DoReadCheck(file_name, FILE_ATTRIBUTE_NORMAL, false);
+}
+
+} // namespace
diff --git a/chromium/chrome_elf/dll_hash.gypi b/chromium/chrome_elf/dll_hash.gypi
new file mode 100644
index 00000000000..9e89a241e42
--- /dev/null
+++ b/chromium/chrome_elf/dll_hash.gypi
@@ -0,0 +1,31 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'targets': [
+ {
+ 'target_name': 'dll_hash',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ ],
+ 'sources': [
+ 'dll_hash/dll_hash.cc',
+ 'dll_hash/dll_hash.h',
+ ],
+ },
+ {
+ 'target_name': 'dll_hash_main',
+ 'type': 'executable',
+ 'dependencies': [
+ 'dll_hash',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'dll_hash/dll_hash_main.cc',
+ ],
+ }
+ ]
+} \ No newline at end of file
diff --git a/chromium/chrome_elf/dll_hash/dll_hash.cc b/chromium/chrome_elf/dll_hash/dll_hash.cc
new file mode 100644
index 00000000000..ecd1491f64f
--- /dev/null
+++ b/chromium/chrome_elf/dll_hash/dll_hash.cc
@@ -0,0 +1,14 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/hash.h"
+#include "chrome_elf/dll_hash/dll_hash.h"
+
+int DllNameToHash(std::string dll_name) {
+ uint32 data = base::Hash(dll_name);
+
+ // Strip off the signed bit because UMA doesn't support negative values,
+ // but takes a signed int as input.
+ return static_cast<int>(data & 0x7fffffff);
+}
diff --git a/chromium/chrome_elf/dll_hash/dll_hash.h b/chromium/chrome_elf/dll_hash/dll_hash.h
new file mode 100644
index 00000000000..82bec8af1cd
--- /dev/null
+++ b/chromium/chrome_elf/dll_hash/dll_hash.h
@@ -0,0 +1,13 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_DLL_HASH_DLL_HASH_H_
+#define CHROME_ELF_DLL_HASH_DLL_HASH_H_
+
+#include <string>
+
+// Convert a dll name to a hash that can be sent via UMA.
+int DllNameToHash(std::string dll_name);
+
+#endif // CHROME_ELF_DLL_HASH_DLL_HASH_H_
diff --git a/chromium/chrome_elf/dll_hash/dll_hash_main.cc b/chromium/chrome_elf/dll_hash/dll_hash_main.cc
new file mode 100644
index 00000000000..a360263af43
--- /dev/null
+++ b/chromium/chrome_elf/dll_hash/dll_hash_main.cc
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This is a utility executable used for generating hashes for dll names
+// for inclusion in tools/metrics/histograms/histograms.xml. Every
+// dll name must have a corresponding entry in the enum there.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "chrome_elf/dll_hash/dll_hash.h"
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <dll name> <dll name> <...>\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Prints hashes for dll names.\n");
+ fprintf(stderr, "Example: %s \"my_dll.dll\" \"user32.dll\"\n", argv[0]);
+ return 1;
+ }
+ for (int i = 1; i < argc; i++) {
+ int hash = DllNameToHash(std::string(argv[i]));
+ printf("<int value=\"%d\" label=\"%s\"/>\n", hash, argv[i]);
+ }
+ return 0;
+}
diff --git a/chromium/chrome_elf/elf_imports_unittest.cc b/chromium/chrome_elf/elf_imports_unittest.cc
new file mode 100644
index 00000000000..136912beac9
--- /dev/null
+++ b/chromium/chrome_elf/elf_imports_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+#include <windows.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/win/pe_image.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ELFImportsTest : public testing::Test {
+ protected:
+ static bool ImportsCallback(const base::win::PEImage &image,
+ LPCSTR module,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) {
+ std::vector<std::string>* import_list =
+ reinterpret_cast<std::vector<std::string>*>(cookie);
+ import_list->push_back(module);
+ return true;
+ }
+
+ void GetImports(const base::FilePath& module_path,
+ std::vector<std::string>* imports) {
+ ASSERT_TRUE(imports != NULL);
+
+ base::MemoryMappedFile module_mmap;
+
+ ASSERT_TRUE(module_mmap.Initialize(module_path));
+ base::win::PEImageAsData pe_image_data(
+ reinterpret_cast<HMODULE>(const_cast<uint8*>(module_mmap.data())));
+ pe_image_data.EnumImportChunks(ELFImportsTest::ImportsCallback, imports);
+ }
+};
+
+TEST_F(ELFImportsTest, ChromeElfSanityCheck) {
+ std::vector<std::string> elf_imports;
+
+ base::FilePath dll;
+ ASSERT_TRUE(PathService::Get(base::DIR_EXE, &dll));
+ dll = dll.Append(L"chrome_elf.dll");
+ GetImports(dll, &elf_imports);
+
+ // Check that ELF has imports.
+ ASSERT_LT(0u, elf_imports.size()) << "Ensure the chrome_elf_unittests "
+ "target was built, instead of chrome_elf_unittests.exe";
+
+ std::vector<std::string>::iterator it(elf_imports.begin());
+
+ static const char* const kValidFilePatterns[] = {
+ "KERNEL32.dll",
+ "MSVC*",
+#if defined(SYZYASAN)
+ "syzyasan_rtl.dll",
+#endif
+ "ADVAPI32.dll"
+ };
+
+ // Make sure all of ELF's imports are in the valid imports list.
+ for (; it != elf_imports.end(); it++) {
+ bool match = false;
+ for (int i = 0; i < arraysize(kValidFilePatterns); ++i) {
+ if (MatchPattern(*it, kValidFilePatterns[i]))
+ match = true;
+ }
+ ASSERT_TRUE(match) << "Illegal import in chrome_elf.dll.";
+ }
+}
+
+TEST_F(ELFImportsTest, ChromeExeSanityCheck) {
+ std::vector<std::string> exe_imports;
+
+ base::FilePath exe;
+ ASSERT_TRUE(PathService::Get(base::DIR_EXE, &exe));
+ exe = exe.Append(L"chrome.exe");
+ GetImports(exe, &exe_imports);
+
+ // Check that chrome.exe has imports.
+ ASSERT_LT(0u, exe_imports.size()) << "Ensure the chrome_elf_unittests "
+ "target was built, instead of chrome_elf_unittests.exe";
+
+ // Chrome.exe's first import must be ELF.
+ EXPECT_EQ("chrome_elf.dll", exe_imports[0]) <<
+ "Illegal import order in chrome.exe (ensure the chrome_elf_unittest "
+ "target was built, instead of just chrome_elf_unittests.exe)";
+}
+
+} // namespace
diff --git a/chromium/chrome_elf/ntdll_cache.cc b/chromium/chrome_elf/ntdll_cache.cc
index e5504421ae4..a0429a45aed 100644
--- a/chromium/chrome_elf/ntdll_cache.cc
+++ b/chromium/chrome_elf/ntdll_cache.cc
@@ -2,50 +2,88 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome_elf/ntdll_cache.h"
+
#include <stdint.h>
#include <windows.h>
-#include "chrome_elf/ntdll_cache.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/pe_image.h"
+#include "chrome_elf/thunk_getter.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/service_resolver.h"
FunctionLookupTable g_ntdll_lookup;
+// Allocate storage for thunks in a page of this module to save on doing
+// an extra allocation at run time.
+#pragma section(".crthunk",read,execute)
+__declspec(allocate(".crthunk")) sandbox::ThunkData g_nt_thunk_storage;
+
+
+
+namespace {
+
+bool EnumExportsCallback(const base::win::PEImage& image,
+ DWORD ordinal,
+ DWORD hint,
+ LPCSTR name,
+ PVOID function_addr,
+ LPCSTR forward,
+ PVOID cookie) {
+ // Our lookup only cares about named functions that are in ntdll, so skip
+ // unnamed or forwarded exports.
+ if (name && function_addr)
+ g_ntdll_lookup[std::string(name)] = function_addr;
+
+ return true;
+}
+
+} // namespace
+
void InitCache() {
HMODULE ntdll_handle = ::GetModuleHandle(L"ntdll.dll");
- // To find the Export Address Table address, we start from the DOS header.
- // The module handle is actually the address of the header.
- IMAGE_DOS_HEADER* dos_header =
- reinterpret_cast<IMAGE_DOS_HEADER*>(ntdll_handle);
- // The e_lfanew is an offset from the DOS header to the NT header. It should
- // never be 0.
- IMAGE_NT_HEADERS* nt_headers = reinterpret_cast<IMAGE_NT_HEADERS*>(
- ntdll_handle + dos_header->e_lfanew / sizeof(uint32_t));
- // For modules that have an import address table, its offset from the
- // DOS header is stored in the second data directory's VirtualAddress.
- if (!nt_headers->OptionalHeader.DataDirectory[0].VirtualAddress)
- return;
-
- BYTE* base_addr = reinterpret_cast<BYTE*>(ntdll_handle);
-
- IMAGE_DATA_DIRECTORY* exports_data_dir =
- &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
-
- IMAGE_EXPORT_DIRECTORY* exports = reinterpret_cast<IMAGE_EXPORT_DIRECTORY*>(
- base_addr + exports_data_dir->VirtualAddress);
-
- WORD* ordinals = reinterpret_cast<WORD*>(
- base_addr + exports->AddressOfNameOrdinals);
- DWORD* names = reinterpret_cast<DWORD*>(
- base_addr + exports->AddressOfNames);
- DWORD* funcs = reinterpret_cast<DWORD*>(
- base_addr + exports->AddressOfFunctions);
- int num_entries = exports->NumberOfNames;
-
- for (int i = 0; i < num_entries; i++) {
- char* name = reinterpret_cast<char*>(base_addr + names[i]);
- WORD ord = ordinals[i];
- DWORD func = funcs[ord];
- FARPROC func_addr = reinterpret_cast<FARPROC>(func + base_addr);
- g_ntdll_lookup[std::string(name)] = func_addr;
+ base::win::PEImage ntdll_image(ntdll_handle);
+
+ ntdll_image.EnumExports(EnumExportsCallback, NULL);
+
+ // If ntdll has already been patched, don't copy it.
+ const bool kRelaxed = false;
+
+ // Create a thunk via the appropriate ServiceResolver instance.
+ scoped_ptr<sandbox::ServiceResolverThunk> thunk(GetThunk(kRelaxed));
+
+ if (thunk.get()) {
+ BYTE* thunk_storage = reinterpret_cast<BYTE*>(&g_nt_thunk_storage);
+
+ // Mark the thunk storage as readable and writeable, since we
+ // are ready to write to it.
+ DWORD old_protect = 0;
+ if (!::VirtualProtect(&g_nt_thunk_storage,
+ sizeof(g_nt_thunk_storage),
+ PAGE_EXECUTE_READWRITE,
+ &old_protect)) {
+ return;
+ }
+
+ size_t storage_used = 0;
+ NTSTATUS ret = thunk->CopyThunk(::GetModuleHandle(sandbox::kNtdllName),
+ "NtCreateFile",
+ thunk_storage,
+ sizeof(sandbox::ThunkData),
+ &storage_used);
+
+ if (!NT_SUCCESS(ret)) {
+ memset(&g_nt_thunk_storage, 0, sizeof(g_nt_thunk_storage));
+ }
+
+ // Ensure that the pointer to the old function can't be changed.
+ ::VirtualProtect(&g_nt_thunk_storage,
+ sizeof(g_nt_thunk_storage),
+ PAGE_EXECUTE_READ,
+ &old_protect);
}
}
diff --git a/chromium/chrome_elf/ntdll_cache.h b/chromium/chrome_elf/ntdll_cache.h
index 4608cf19367..5e4fb2bf7a3 100644
--- a/chromium/chrome_elf/ntdll_cache.h
+++ b/chromium/chrome_elf/ntdll_cache.h
@@ -7,9 +7,15 @@
#include "chrome_elf/chrome_elf_types.h"
+namespace sandbox {
+struct ThunkData;
+}
+
// Caches the addresses of all functions exported by ntdll in |g_ntdll_lookup|.
void InitCache();
extern FunctionLookupTable g_ntdll_lookup;
+extern sandbox::ThunkData g_nt_thunk_storage;
+
#endif // CHROME_ELF_NTDLL_CACHE_H_
diff --git a/chromium/chrome_elf/thunk_getter.cc b/chromium/chrome_elf/thunk_getter.cc
new file mode 100644
index 00000000000..8421e5eecf1
--- /dev/null
+++ b/chromium/chrome_elf/thunk_getter.cc
@@ -0,0 +1,142 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdint.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/service_resolver.h"
+
+namespace {
+enum Version {
+ VERSION_PRE_XP_SP2 = 0, // Not supported.
+ VERSION_XP_SP2,
+ VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2.
+ VERSION_VISTA, // Also includes Windows Server 2008.
+ VERSION_WIN7, // Also includes Windows Server 2008 R2.
+ VERSION_WIN8, // Also includes Windows Server 2012.
+ VERSION_WIN8_1,
+ VERSION_WIN_LAST, // Indicates error condition.
+};
+
+// Whether a process is running under WOW64 (the wrapper that allows 32-bit
+// processes to run on 64-bit versions of Windows). This will return
+// WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
+// Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g.
+// the process does not have sufficient access rights to determine this.
+enum WOW64Status { WOW64_DISABLED, WOW64_ENABLED, WOW64_UNKNOWN, };
+
+WOW64Status GetWOW64StatusForCurrentProcess() {
+ typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
+ IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
+ GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
+ if (!is_wow64_process)
+ return WOW64_DISABLED;
+ BOOL is_wow64 = FALSE;
+ if (!is_wow64_process(GetCurrentProcess(), &is_wow64))
+ return WOW64_UNKNOWN;
+ return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
+class OSInfo {
+ public:
+ struct VersionNumber {
+ int major;
+ int minor;
+ int build;
+ };
+
+ struct ServicePack {
+ int major;
+ int minor;
+ };
+
+ OSInfo() {
+ OSVERSIONINFOEX version_info = {sizeof(version_info)};
+ GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
+ version_number_.major = version_info.dwMajorVersion;
+ version_number_.minor = version_info.dwMinorVersion;
+ version_number_.build = version_info.dwBuildNumber;
+ if ((version_number_.major == 5) && (version_number_.minor > 0)) {
+ // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
+ version_ =
+ (version_number_.minor == 1) ? VERSION_XP_SP2 : VERSION_SERVER_2003;
+ if (version_ == VERSION_XP_SP2 && version_info.wServicePackMajor < 2)
+ version_ = VERSION_PRE_XP_SP2;
+ } else if (version_number_.major == 6) {
+ switch (version_number_.minor) {
+ case 0:
+ // Treat Windows Server 2008 the same as Windows Vista.
+ version_ = VERSION_VISTA;
+ break;
+ case 1:
+ // Treat Windows Server 2008 R2 the same as Windows 7.
+ version_ = VERSION_WIN7;
+ break;
+ case 2:
+ // Treat Windows Server 2012 the same as Windows 8.
+ version_ = VERSION_WIN8;
+ break;
+ default:
+ version_ = VERSION_WIN8_1;
+ break;
+ }
+ } else if (version_number_.major > 6) {
+ version_ = VERSION_WIN_LAST;
+ } else {
+ version_ = VERSION_PRE_XP_SP2;
+ }
+
+ service_pack_.major = version_info.wServicePackMajor;
+ service_pack_.minor = version_info.wServicePackMinor;
+ }
+
+ Version version() const { return version_; }
+ VersionNumber version_number() const { return version_number_; }
+ ServicePack service_pack() const { return service_pack_; }
+
+ private:
+ Version version_;
+ VersionNumber version_number_;
+ ServicePack service_pack_;
+
+ DISALLOW_COPY_AND_ASSIGN(OSInfo);
+};
+
+} // namespace
+
+sandbox::ServiceResolverThunk* GetThunk(bool relaxed) {
+ // Create a thunk via the appropriate ServiceResolver instance.
+ sandbox::ServiceResolverThunk* thunk = NULL;
+
+ // No thunks for unsupported OS versions.
+ OSInfo os_info;
+ if (os_info.version() <= VERSION_PRE_XP_SP2)
+ return thunk;
+
+ // Pseudo-handle, no need to close.
+ HANDLE current_process = ::GetCurrentProcess();
+
+#if defined(_WIN64)
+ // ServiceResolverThunk can handle all the formats in 64-bit (instead only
+ // handling one like it does in 32-bit versions).
+ thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
+#else
+ if (GetWOW64StatusForCurrentProcess() == WOW64_ENABLED) {
+ if (os_info.version() >= VERSION_WIN8)
+ thunk = new sandbox::Wow64W8ResolverThunk(current_process, relaxed);
+ else
+ thunk = new sandbox::Wow64ResolverThunk(current_process, relaxed);
+ } else if (os_info.version() >= VERSION_WIN8) {
+ thunk = new sandbox::Win8ResolverThunk(current_process, relaxed);
+ } else {
+ thunk = new sandbox::ServiceResolverThunk(current_process, relaxed);
+ }
+#endif
+
+ return thunk;
+}
diff --git a/chromium/chrome_elf/thunk_getter.h b/chromium/chrome_elf/thunk_getter.h
new file mode 100644
index 00000000000..5bc20fe81e5
--- /dev/null
+++ b/chromium/chrome_elf/thunk_getter.h
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_ELF_THUNK_GETTER_H_
+#define CHROME_ELF_THUNK_GETTER_H_
+
+namespace sandbox {
+class ServiceResolverThunk;
+}
+
+// Creates a |ServiceResolverThunk| based on the OS version. Ownership of the
+// resulting thunk is passed to the caller.
+sandbox::ServiceResolverThunk* GetThunk(bool relaxed);
+
+#endif // CHROME_ELF_THUNK_GETTER_H_
diff --git a/chromium/chrome_elf/version_assembly_manifest.template b/chromium/chrome_elf/version_assembly_manifest.template
deleted file mode 100644
index 153194c3d31..00000000000
--- a/chromium/chrome_elf/version_assembly_manifest.template
+++ /dev/null
@@ -1,8 +0,0 @@
-<assembly
- xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
- <assemblyIdentity
- name='@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
- version='@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
- type='win32'/>
- <file name='chrome_elf.dll'/>
-</assembly> \ No newline at end of file
diff --git a/chromium/chrome_elf/version_assembly_manifest_action.gypi b/chromium/chrome_elf/version_assembly_manifest_action.gypi
deleted file mode 100644
index 9c443153321..00000000000
--- a/chromium/chrome_elf/version_assembly_manifest_action.gypi
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This file contains an action which can be used to construct a manifest file
-# with the same name as the version directory so that chrome.exe identifies the
-# version directory as an assembly. This will be copied over to the version
-# directory by the installer script.
-
-# To use this the following variables need to be defined:
-# version_path: string: path to file containing version data (e.g.
-# chrome/VERSION).
-# version_py_path: string: path to file containing version script (e.g.
-# chrome/tools/build/version.py).
-# version_full: string: version string in W.X.Y.Z form.
-
-
-{
- 'variables': {
- 'template_input_path':
- '<(DEPTH)/chrome_elf/version_assembly_manifest.template',
- },
- 'inputs': [
- '<(template_input_path)',
- '<(version_path)',
- ],
- 'outputs': [
- '<(PRODUCT_DIR)/<(version_full).manifest',
- ],
- 'action': [
- 'python', '<(version_py_path)',
- '-f', '<(version_path)',
- '<(template_input_path)',
- '<@(_outputs)',
- ],
- 'message': 'Generating <@(_outputs)',
-} \ No newline at end of file