Commit 5446d89c authored by pennymac's avatar pennymac Committed by Commit bot

[chrome_elf] Big cleanup and removing dependencies that recently crept in. PART 1.

- Moving all crash related APIs into one place (and out of chrome_elf_main).
- Started to clean up external dependencies - starting with hook_utils.
- Removed dependency on base/win/iat_patch_function.

BUG=631771

Committed: https://crrev.com/d2767f8b41a8f7f70bddbd0783a8ef27a9370e58
Review-Url: https://codereview.chromium.org/2183263003
Cr-Original-Commit-Position: refs/heads/master@{#411982}
Cr-Commit-Position: refs/heads/master@{#414898}
parent cf429990
...@@ -33,9 +33,6 @@ windows_manifest("chrome_elf_manifest") { ...@@ -33,9 +33,6 @@ windows_manifest("chrome_elf_manifest") {
# in the world. # in the world.
shared_library("chrome_elf") { shared_library("chrome_elf") {
sources = [ sources = [
"//chrome/app/chrome_crash_reporter_client_win.cc",
"//chrome/app/chrome_crash_reporter_client_win.h",
"//chrome/common/chrome_result_codes.h",
"chrome_elf.def", "chrome_elf.def",
"chrome_elf_main.cc", "chrome_elf_main.cc",
"chrome_elf_main.h", "chrome_elf_main.h",
...@@ -44,31 +41,24 @@ shared_library("chrome_elf") { ...@@ -44,31 +41,24 @@ shared_library("chrome_elf") {
":blacklist", ":blacklist",
":chrome_elf_manifest", ":chrome_elf_manifest",
":chrome_elf_resources", ":chrome_elf_resources",
":chrome_elf_security",
":constants", ":constants",
":crash",
":hook_util", ":hook_util",
"//base", ":security",
"//build/config/sanitizers:deps", "//build/config/sanitizers:deps",
"//chrome/install_static:install_static_util", "//chrome/install_static:install_static_util",
"//chrome_elf/nt_registry:nt_registry", "//chrome_elf/nt_registry:nt_registry",
"//components/crash/content/app",
"//components/crash/core/common",
"//content/public/common:result_codes",
"//third_party/crashpad/crashpad/client:client",
] ]
configs += [ "//build/config/win:windowed" ] configs += [ "//build/config/win:windowed" ]
configs -= [ "//build/config/win:console" ] configs -= [ "//build/config/win:console" ]
# Delay loads in this list will prevent user32.dll
# from loading too early.
ldflags = [ ldflags = [
"/NODEFAULTLIB:user32.lib", "/DELAYLOAD:advapi32.dll",
"/DELAYLOAD:dbghelp.dll", "/DELAYLOAD:dbghelp.dll",
"/DELAYLOAD:ole32.dll",
"/DELAYLOAD:psapi.dll",
"/DELAYLOAD:rpcrt4.dll", "/DELAYLOAD:rpcrt4.dll",
"/DELAYLOAD:shell32.dll",
"/DELAYLOAD:user32.dll",
"/DELAYLOAD:winhttp.dll",
"/DELAYLOAD:winmm.dll", "/DELAYLOAD:winmm.dll",
"/DELAYLOAD:ws2_32.dll",
] ]
if (current_cpu == "x86") { if (current_cpu == "x86") {
# Don"t set an x64 base address (to avoid breaking HE-ASLR). # Don"t set an x64 base address (to avoid breaking HE-ASLR).
...@@ -80,7 +70,7 @@ shared_library("chrome_elf") { ...@@ -80,7 +70,7 @@ shared_library("chrome_elf") {
## source sets ## source sets
##------------------------------------------------------------------------------ ##------------------------------------------------------------------------------
source_set("chrome_elf_security") { source_set("security") {
sources = [ sources = [
"chrome_elf_security.cc", "chrome_elf_security.cc",
"chrome_elf_security.h", "chrome_elf_security.h",
...@@ -129,30 +119,48 @@ static_library("blacklist") { ...@@ -129,30 +119,48 @@ static_library("blacklist") {
"blacklist/blacklist.h", "blacklist/blacklist.h",
"blacklist/blacklist_interceptions.cc", "blacklist/blacklist_interceptions.cc",
"blacklist/blacklist_interceptions.h", "blacklist/blacklist_interceptions.h",
"blacklist/crashpad_helper.cc",
"blacklist/crashpad_helper.h",
] ]
public_deps = [ public_deps = [
"//sandbox", "//sandbox",
] ]
deps = [ deps = [
":constants", ":constants",
":crash",
":hook_util", ":hook_util",
"//base:base_static", # pe_image
"//chrome/install_static:install_static_util", "//chrome/install_static:install_static_util",
"//chrome_elf/nt_registry:nt_registry", "//chrome_elf/nt_registry:nt_registry",
]
}
# Still uses base/win/pe_image.h static_library("crash") {
"//base", sources = [
"//third_party/crashpad/crashpad/client:client", "../chrome/app/chrome_crash_reporter_client_win.cc",
"../chrome/app/chrome_crash_reporter_client_win.h",
"../chrome/common/chrome_result_codes.h",
"crash/crash_helper.cc",
"crash/crash_helper.h",
]
deps = [
":hook_util",
"//base:base", # This needs to go. DEP of app, crash_keys, client.
"//base:base_static", # pe_image
"//chrome/install_static:install_static_util",
"//components/crash/content/app:app",
"//components/crash/core/common", # crash_keys
"//content/public/common:result_codes",
"//third_party/crashpad/crashpad/client:client", # DumpWithoutCrash
] ]
} }
static_library("hook_util") { static_library("hook_util") {
sources = [ sources = [
"hook_util/thunk_getter.cc", "../base/macros.h",
"hook_util/thunk_getter.h", "hook_util/hook_util.cc",
"hook_util/hook_util.h",
] ]
deps = [ deps = [
"//base:base_static", # pe_image
"//sandbox", "//sandbox",
] ]
} }
...@@ -167,15 +175,18 @@ test("chrome_elf_unittests") { ...@@ -167,15 +175,18 @@ test("chrome_elf_unittests") {
"blacklist/test/blacklist_test.cc", "blacklist/test/blacklist_test.cc",
"chrome_elf_util_unittest.cc", "chrome_elf_util_unittest.cc",
"elf_imports_unittest.cc", "elf_imports_unittest.cc",
"hook_util/test/hook_util_test.cc",
"run_all_unittests.cc", "run_all_unittests.cc",
] ]
include_dirs = [ "$target_gen_dir" ] include_dirs = [ "$target_gen_dir" ]
deps = [ deps = [
":blacklist", ":blacklist",
":blacklist_test_main_dll", ":blacklist_test_main_dll",
":chrome_elf_security",
":constants", ":constants",
":crash",
":hook_util", ":hook_util",
":hook_util_test_dll",
":security",
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//chrome", "//chrome",
...@@ -199,17 +210,15 @@ test("chrome_elf_unittests") { ...@@ -199,17 +210,15 @@ test("chrome_elf_unittests") {
":blacklist_test_dll_3", ":blacklist_test_dll_3",
":chrome_elf", ":chrome_elf",
] ]
# Don't want the test-specific dependencies to affect ChromeElfLoadSanityTest.
# In particular, a few system DLLs cause user32 to be loaded, which is bad.
ldflags = [ ldflags = [
"/DELAYLOAD:dbghelp.dll", "/DELAYLOAD:advapi32.dll",
"/DELAYLOAD:ole32.dll", "/DELAYLOAD:ole32.dll",
"/DELAYLOAD:psapi.dll",
"/DELAYLOAD:rpcrt4.dll",
"/DELAYLOAD:shell32.dll", "/DELAYLOAD:shell32.dll",
"/DELAYLOAD:shlwapi.dll",
"/DELAYLOAD:user32.dll", "/DELAYLOAD:user32.dll",
"/DELAYLOAD:winhttp.dll",
"/DELAYLOAD:winmm.dll", "/DELAYLOAD:winmm.dll",
"/DELAYLOAD:ws2_32.dll",
] ]
} }
...@@ -225,18 +234,6 @@ shared_library("blacklist_test_main_dll") { ...@@ -225,18 +234,6 @@ shared_library("blacklist_test_main_dll") {
"//chrome/install_static:install_static_util", "//chrome/install_static:install_static_util",
"//chrome_elf/nt_registry:nt_registry", "//chrome_elf/nt_registry:nt_registry",
] ]
ldflags = [
"/NODEFAULTLIB:user32.lib",
"/DELAYLOAD:dbghelp.dll",
"/DELAYLOAD:ole32.dll",
"/DELAYLOAD:psapi.dll",
"/DELAYLOAD:rpcrt4.dll",
"/DELAYLOAD:shell32.dll",
"/DELAYLOAD:user32.dll",
"/DELAYLOAD:winhttp.dll",
"/DELAYLOAD:winmm.dll",
"/DELAYLOAD:ws2_32.dll",
]
} }
loadable_module("blacklist_test_dll_1") { loadable_module("blacklist_test_dll_1") {
...@@ -272,3 +269,13 @@ loadable_module("blacklist_test_dll_3") { ...@@ -272,3 +269,13 @@ loadable_module("blacklist_test_dll_3") {
"//build/config/sanitizers:deps", "//build/config/sanitizers:deps",
] ]
} }
shared_library("hook_util_test_dll") {
sources = [
"hook_util/test/hook_util_test_dll.cc",
"hook_util/test/hook_util_test_dll.h",
]
deps = [
"//build/config/sanitizers:deps",
]
}
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
'blacklist/blacklist.h', 'blacklist/blacklist.h',
'blacklist/blacklist_interceptions.cc', 'blacklist/blacklist_interceptions.cc',
'blacklist/blacklist_interceptions.h', 'blacklist/blacklist_interceptions.h',
'blacklist/crashpad_helper.cc',
'blacklist/crashpad_helper.h',
], ],
'dependencies': [ 'dependencies': [
'../base/base.gyp:base', '../base/base.gyp:base',
...@@ -24,7 +22,6 @@ ...@@ -24,7 +22,6 @@
'../chrome_elf/chrome_elf.gyp:chrome_elf_constants', '../chrome_elf/chrome_elf.gyp:chrome_elf_constants',
'../chrome_elf/chrome_elf.gyp:chrome_elf_hook_util', '../chrome_elf/chrome_elf.gyp:chrome_elf_hook_util',
'../chrome_elf/nt_registry/nt_registry.gyp:chrome_elf_nt_registry', '../chrome_elf/nt_registry/nt_registry.gyp:chrome_elf_nt_registry',
'../components/components.gyp:crash_component',
'../sandbox/sandbox.gyp:sandbox', '../sandbox/sandbox.gyp:sandbox',
], ],
}, },
...@@ -38,6 +35,7 @@ ...@@ -38,6 +35,7 @@
'dependencies': [ 'dependencies': [
'../base/base.gyp:base', '../base/base.gyp:base',
'../chrome/chrome.gyp:install_static_util', '../chrome/chrome.gyp:install_static_util',
'../chrome_elf/chrome_elf.gyp:chrome_elf_crash',
'../chrome_elf/nt_registry/nt_registry.gyp:chrome_elf_nt_registry', '../chrome_elf/nt_registry/nt_registry.gyp:chrome_elf_nt_registry',
'blacklist', 'blacklist',
], ],
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include "chrome/install_static/install_util.h" #include "chrome/install_static/install_util.h"
#include "chrome_elf/blacklist/blacklist_interceptions.h" #include "chrome_elf/blacklist/blacklist_interceptions.h"
#include "chrome_elf/chrome_elf_constants.h" #include "chrome_elf/chrome_elf_constants.h"
#include "chrome_elf/hook_util/thunk_getter.h" #include "chrome_elf/hook_util/hook_util.h"
#include "chrome_elf/nt_registry/nt_registry.h" #include "chrome_elf/nt_registry/nt_registry.h"
#include "sandbox/win/src/interception_internal.h" #include "sandbox/win/src/interception_internal.h"
#include "sandbox/win/src/internal_types.h" #include "sandbox/win/src/internal_types.h"
...@@ -291,7 +291,7 @@ bool Initialize(bool force) { ...@@ -291,7 +291,7 @@ bool Initialize(bool force) {
const bool kRelaxed = false; const bool kRelaxed = false;
// Create a thunk via the appropriate ServiceResolver instance. // Create a thunk via the appropriate ServiceResolver instance.
sandbox::ServiceResolverThunk* thunk = GetThunk(kRelaxed); sandbox::ServiceResolverThunk* thunk = elf_hook::HookSystemService(kRelaxed);
// Don't try blacklisting on unsupported OS versions. // Don't try blacklisting on unsupported OS versions.
if (!thunk) if (!thunk)
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
// base_static (see base/base.gyp) are allowed here. // base_static (see base/base.gyp) are allowed here.
#include "base/win/pe_image.h" #include "base/win/pe_image.h"
#include "chrome_elf/blacklist/blacklist.h" #include "chrome_elf/blacklist/blacklist.h"
#include "chrome_elf/blacklist/crashpad_helper.h" #include "chrome_elf/crash/crash_helper.h"
#include "sandbox/win/src/internal_types.h" #include "sandbox/win/src/internal_types.h"
#include "sandbox/win/src/nt_internals.h" #include "sandbox/win/src/nt_internals.h"
#include "sandbox/win/src/sandbox_nt_util.h" #include "sandbox/win/src/sandbox_nt_util.h"
...@@ -262,7 +262,7 @@ BlNtMapViewOfSection(NtMapViewOfSectionFunction orig_MapViewOfSection, ...@@ -262,7 +262,7 @@ BlNtMapViewOfSection(NtMapViewOfSectionFunction orig_MapViewOfSection,
base, zero_bits, commit_size, offset, base, zero_bits, commit_size, offset,
view_size, inherit, allocation_type, view_size, inherit, allocation_type,
protect); protect);
} __except(GenerateCrashDump(GetExceptionInformation())) { } __except (elf_crash::GenerateCrashDump(GetExceptionInformation())) {
} }
return ret; return ret;
......
...@@ -40,20 +40,16 @@ ...@@ -40,20 +40,16 @@
'chrome_elf.def', 'chrome_elf.def',
'chrome_elf_main.cc', 'chrome_elf_main.cc',
'chrome_elf_main.h', 'chrome_elf_main.h',
'../chrome/app/chrome_crash_reporter_client_win.cc',
'../chrome/app/chrome_crash_reporter_client_win.h',
'<(SHARED_INTERMEDIATE_DIR)/chrome_elf/chrome_elf_version.rc', '<(SHARED_INTERMEDIATE_DIR)/chrome_elf/chrome_elf_version.rc',
], ],
'dependencies': [ 'dependencies': [
'../chrome/chrome.gyp:install_static_util', '../chrome/chrome.gyp:install_static_util',
'blacklist', 'blacklist',
'chrome_elf_crash',
'chrome_elf_hook_util', 'chrome_elf_hook_util',
'chrome_elf_resources', 'chrome_elf_resources',
'chrome_elf_security', 'chrome_elf_security',
'nt_registry/nt_registry.gyp:chrome_elf_nt_registry', 'nt_registry/nt_registry.gyp:chrome_elf_nt_registry',
'../chrome/chrome.gyp:install_static_util',
'../components/components.gyp:crash_component',
'../components/components.gyp:crash_core_common',
], ],
'msvs_settings': { 'msvs_settings': {
'VCLinkerTool': { 'VCLinkerTool': {
...@@ -88,6 +84,28 @@ ...@@ -88,6 +84,28 @@
'chrome_elf_constants.h', 'chrome_elf_constants.h',
], ],
}, },
{
'target_name': 'chrome_elf_crash',
'type': 'static_library',
'include_dirs': [
'..',
],
'sources': [
'../chrome/app/chrome_crash_reporter_client_win.cc',
'../chrome/app/chrome_crash_reporter_client_win.h',
'../chrome/common/chrome_result_codes.h',
'crash/crash_helper.cc',
'crash/crash_helper.h',
],
'dependencies': [
'../base/base.gyp:base', # This needs to go.
'../base/base.gyp:base_static', # pe_image
'../chrome/chrome.gyp:install_static_util',
'../components/components.gyp:crash_component',
'../components/components.gyp:crash_core_common', #crash_keys
'chrome_elf_hook_util',
],
},
{ {
'target_name': 'chrome_elf_hook_util', 'target_name': 'chrome_elf_hook_util',
'type': 'static_library', 'type': 'static_library',
...@@ -95,8 +113,13 @@ ...@@ -95,8 +113,13 @@
'..', '..',
], ],
'sources': [ 'sources': [
'hook_util/thunk_getter.cc', '../base/macros.h',
'hook_util/thunk_getter.h', 'hook_util/hook_util.cc',
'hook_util/hook_util.h',
],
'dependencies': [
'../base/base.gyp:base_static', # pe_image
'../sandbox/sandbox.gyp:sandbox',
], ],
}, },
{ {
...@@ -143,6 +166,7 @@ ...@@ -143,6 +166,7 @@
'blacklist_test_dll_2', 'blacklist_test_dll_2',
'blacklist_test_dll_3', 'blacklist_test_dll_3',
'blacklist_test_main_dll', 'blacklist_test_main_dll',
'chrome_elf_crash',
'chrome_elf_hook_util', 'chrome_elf_hook_util',
'chrome_elf_security', 'chrome_elf_security',
'nt_registry/nt_registry.gyp:chrome_elf_nt_registry', 'nt_registry/nt_registry.gyp:chrome_elf_nt_registry',
......
...@@ -4,102 +4,40 @@ ...@@ -4,102 +4,40 @@
#include "chrome_elf/chrome_elf_main.h" #include "chrome_elf/chrome_elf_main.h"
#include <assert.h>
#include <windows.h> #include <windows.h>
#include <algorithm>
#include "base/lazy_instance.h"
#include "base/strings/string16.h"
#include "base/win/iat_patch_function.h"
#include "build/build_config.h"
#include "chrome/app/chrome_crash_reporter_client_win.h"
#include "chrome/install_static/install_util.h" #include "chrome/install_static/install_util.h"
#include "chrome_elf/blacklist/blacklist.h" #include "chrome_elf/blacklist/blacklist.h"
#include "chrome_elf/blacklist/crashpad_helper.h" #include "chrome_elf/crash/crash_helper.h"
#include "chrome_elf/chrome_elf_constants.h"
#include "components/crash/content/app/crashpad.h"
#include "components/crash/core/common/crash_keys.h"
namespace {
base::LazyInstance<std::vector<crash_reporter::Report>>::Leaky g_crash_reports =
LAZY_INSTANCE_INITIALIZER;
#if !defined(ADDRESS_SANITIZER)
// chrome_elf loads early in the process and initializes Crashpad. That in turn
// uses the SetUnhandledExceptionFilter API to set a top level exception
// handler for the process. When the process eventually initializes, CRT sets
// an exception handler which calls TerminateProcess which effectively bypasses
// us. Ideally we want to be at the top of the unhandled exception filter
// chain. However we don't have a good way of intercepting the
// SetUnhandledExceptionFilter API in the sandbox. EAT patching kernel32 or
// kernelbase should ideally work. However the kernel32 kernelbase dlls are
// prebound which causes EAT patching to not work. Sidestep works. However it
// is only supported for 32 bit. For now we use IAT patching for the
// executable.
// TODO(ananta).
// Check if it is possible to fix EAT patching or use sidestep patching for
// 32 bit and 64 bit for this purpose.
base::win::IATPatchFunction g_set_unhandled_exception_filter;
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
SetUnhandledExceptionFilterPatch(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
// Don't set the exception filter. Please see above for comments.
return nullptr;
}
// Please refer above to more information about why we intercept the
// SetUnhandledExceptionFilter API.
void DisableSetUnhandledExceptionFilter() {
DWORD patched = g_set_unhandled_exception_filter.PatchFromModule(
GetModuleHandle(nullptr), "kernel32.dll", "SetUnhandledExceptionFilter",
SetUnhandledExceptionFilterPatch);
CHECK(patched == 0);
}
#endif // !defined(ADDRESS_SANITIZER)
} // namespace
void SignalChromeElf() { void SignalChromeElf() {
blacklist::ResetBeacon(); blacklist::ResetBeacon();
} }
// This helper is invoked by code in chrome.dll to retrieve the crash reports.
// See CrashUploadListCrashpad. Note that we do not pass an std::vector here,
// because we do not want to allocate/free in different modules. The returned
// pointer is read-only.
extern "C" __declspec(dllexport) void GetCrashReportsImpl(
const crash_reporter::Report** reports,
size_t* report_count) {
crash_reporter::GetReports(g_crash_reports.Pointer());
*reports = g_crash_reports.Pointer()->data();
*report_count = g_crash_reports.Pointer()->size();
}
// This helper is invoked by debugging code in chrome to register the client
// id.
extern "C" __declspec(dllexport) void SetMetricsClientId(
const char* client_id) {
if (client_id)
crash_keys::SetMetricsClientIdFromGUID(client_id);
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) { BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) { if (reason == DLL_PROCESS_ATTACH) {
ChromeCrashReporterClient::InitializeCrashReportingForProcess(); if (!elf_crash::InitializeCrashReporting()) {
// CRT on initialization installs an exception filter which calls #ifdef _DEBUG
// TerminateProcess. We need to hook CRT's attempt to set an exception assert(false);
// handler and ignore it. Don't do this when ASan is present, or ASan will #endif // _DEBUG
// fail to install its own unhandled exception filter. }
// CRT on initialization installs an exception filter which calls
// TerminateProcess. We need to hook CRT's attempt to set an exception.
// NOTE: Do not hook if ASan is present, or ASan will fail to install
// its own unhandled exception filter.
#if !defined(ADDRESS_SANITIZER) #if !defined(ADDRESS_SANITIZER)
DisableSetUnhandledExceptionFilter(); elf_crash::DisableSetUnhandledExceptionFilter();
#endif #endif // !defined (ADDRESS_SANITIZER)
install_static::InitializeProcessType(); install_static::InitializeProcessType();
__try { __try {
blacklist::Initialize(false); // Don't force, abort if beacon is present. blacklist::Initialize(false); // Don't force, abort if beacon is present.
} __except(GenerateCrashDump(GetExceptionInformation())) { } __except (elf_crash::GenerateCrashDump(GetExceptionInformation())) {
} }
} else if (reason == DLL_PROCESS_DETACH) {
elf_crash::ShutdownCrashReporting();
} }
return TRUE; return TRUE;
} }
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "chrome_elf/chrome_elf_constants.h" #include "chrome_elf/chrome_elf_constants.h"
#include "chrome_elf/nt_registry/nt_registry.h" #include "chrome_elf/nt_registry/nt_registry.h"
namespace elf_security {
void EarlyBrowserSecurity() { void EarlyBrowserSecurity() {
typedef decltype(SetProcessMitigationPolicy)* SetProcessMitigationPolicyFunc; typedef decltype(SetProcessMitigationPolicy)* SetProcessMitigationPolicyFunc;
...@@ -47,3 +49,4 @@ void EarlyBrowserSecurity() { ...@@ -47,3 +49,4 @@ void EarlyBrowserSecurity() {
} }
return; return;
} }
} // namespace elf_security
...@@ -5,7 +5,11 @@ ...@@ -5,7 +5,11 @@
#ifndef CHROME_ELF_CHROME_ELF_SECURITY_H_ #ifndef CHROME_ELF_CHROME_ELF_SECURITY_H_
#define CHROME_ELF_CHROME_ELF_SECURITY_H_ #define CHROME_ELF_CHROME_ELF_SECURITY_H_
namespace elf_security {
// Setup any early browser-process security. // Setup any early browser-process security.
void EarlyBrowserSecurity(); void EarlyBrowserSecurity();
} // namespace elf_security
#endif // CHROME_ELF_CHROME_ELF_SECURITY_H_ #endif // CHROME_ELF_CHROME_ELF_SECURITY_H_
...@@ -112,12 +112,12 @@ TEST(ChromeElfUtilTest, BrowserProcessSecurityTest) { ...@@ -112,12 +112,12 @@ TEST(ChromeElfUtilTest, BrowserProcessSecurityTest) {
// First, ensure that the emergency-off finch signal works. // First, ensure that the emergency-off finch signal works.
EXPECT_TRUE(SetSecurityFinchFlag(true)); EXPECT_TRUE(SetSecurityFinchFlag(true));
EarlyBrowserSecurity(); elf_security::EarlyBrowserSecurity();
EXPECT_FALSE(IsSecuritySet()); EXPECT_FALSE(IsSecuritySet());
EXPECT_TRUE(SetSecurityFinchFlag(false)); EXPECT_TRUE(SetSecurityFinchFlag(false));
// Second, test that the process mitigation is set when no finch signal. // Second, test that the process mitigation is set when no finch signal.
EarlyBrowserSecurity(); elf_security::EarlyBrowserSecurity();
EXPECT_TRUE(IsSecuritySet()); EXPECT_TRUE(IsSecuritySet());
} }
......
// Copyright 2016 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/crash/crash_helper.h"
#include <assert.h>
#include <windows.h>
#include <algorithm>
#include <string>
#include <vector>
#include "chrome/app/chrome_crash_reporter_client_win.h"
#include "chrome_elf/hook_util/hook_util.h"
#include "components/crash/content/app/crashpad.h"
#include "components/crash/core/common/crash_keys.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
namespace {
// Crash handling from elf is only enabled for the chrome.exe process.
// Use this global to safely handle the rare case where elf may not be in that
// process (e.g. tests).
bool g_crash_helper_enabled = false;
// Global pointer to a vector of crash reports.
// This structure will be initialized in InitializeCrashReportingForProcess()
// and cleaned up in DllDetachCrashReportingCleanup().
std::vector<crash_reporter::Report>* g_crash_reports = nullptr;
// chrome_elf loads early in the process and initializes Crashpad. That in turn
// uses the SetUnhandledExceptionFilter API to set a top level exception
// handler for the process. When the process eventually initializes, CRT sets
// an exception handler which calls TerminateProcess which effectively bypasses
// us. Ideally we want to be at the top of the unhandled exception filter
// chain. However we don't have a good way of intercepting the
// SetUnhandledExceptionFilter API in the sandbox. EAT patching kernel32 or
// kernelbase should ideally work. However the kernel32 kernelbase dlls are
// prebound which causes EAT patching to not work. Sidestep works. However it
// is only supported for 32 bit. For now we use IAT patching for the
// executable.
// TODO(ananta).
// Check if it is possible to fix EAT patching or use sidestep patching for
// 32 bit and 64 bit for this purpose.
elf_hook::IATHook* g_set_unhandled_exception_filter = nullptr;
// Hook function, which ignores the request to set an unhandled-exception
// filter.
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
SetUnhandledExceptionFilterPatch(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
// Don't set the exception filter. Please see above for comments.
return nullptr;
}
} // namespace
//------------------------------------------------------------------------------
// Public chrome_elf crash APIs
//------------------------------------------------------------------------------
namespace elf_crash {
// NOTE: This function will be called from DllMain during DLL_PROCESS_ATTACH
// (while we have the loader lock), so do not misbehave.
bool InitializeCrashReporting() {
#ifdef _DEBUG
assert(g_crash_reports == nullptr);
assert(g_set_unhandled_exception_filter == nullptr);
#endif // _DEBUG
// No global objects with destructors, so using global pointers.
// DllMain on detach will clean these up.
g_crash_reports = new std::vector<crash_reporter::Report>;
g_set_unhandled_exception_filter = new elf_hook::IATHook();
ChromeCrashReporterClient::InitializeCrashReportingForProcess();
g_crash_helper_enabled = true;
return true;
}
// NOTE: This function will be called from DllMain during DLL_PROCESS_DETACH
// (while we have the loader lock), so do not misbehave.
void ShutdownCrashReporting() {
if (g_crash_reports != nullptr) {
g_crash_reports->clear();
delete g_crash_reports;
}
if (g_set_unhandled_exception_filter != nullptr) {
delete g_set_unhandled_exception_filter;
}
}
// Please refer to the comment on g_set_unhandled_exception_filter for more
// information about why we intercept the SetUnhandledExceptionFilter API.
void DisableSetUnhandledExceptionFilter() {
if (!g_crash_helper_enabled)
return;
if (g_set_unhandled_exception_filter->Hook(
::GetModuleHandle(nullptr), "kernel32.dll",
"SetUnhandledExceptionFilter",
SetUnhandledExceptionFilterPatch) != NO_ERROR) {
#ifdef _DEBUG
assert(false);
#endif //_DEBUG
}
}
int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers) {
if (g_crash_helper_enabled)
crashpad::CrashpadClient::DumpWithoutCrash(
*(exception_pointers->ContextRecord));
return EXCEPTION_CONTINUE_SEARCH;
}
} // namespace elf_crash
//------------------------------------------------------------------------------
// Exported crash APIs for the rest of the process.
//------------------------------------------------------------------------------
// This helper is invoked by code in chrome.dll to retrieve the crash reports.
// See CrashUploadListCrashpad. Note that we do not pass a std::vector here,
// because we do not want to allocate/free in different modules. The returned
// pointer is read-only.
//
// NOTE: Since the returned pointer references read-only memory that will be
// cleaned up when this DLL unloads, be careful not to reference the memory
// beyond that point (e.g. during tests).
extern "C" __declspec(dllexport) void GetCrashReportsImpl(
const crash_reporter::Report** reports,
size_t* report_count) {
if (!g_crash_helper_enabled)
return;
crash_reporter::GetReports(g_crash_reports);
*reports = g_crash_reports->data();
*report_count = g_crash_reports->size();
}
// This helper is invoked by debugging code in chrome to register the client
// id.
extern "C" __declspec(dllexport) void SetMetricsClientId(
const char* client_id) {
if (!g_crash_helper_enabled)
return;
if (client_id)
crash_keys::SetMetricsClientIdFromGUID(client_id);
}
...@@ -2,14 +2,31 @@ ...@@ -2,14 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_ELF_BLACKLIST_CRASHPAD_HELPER_H_ #ifndef CHROME_ELF_CRASH_CRASH_HELPER_H_
#define CHROME_ELF_BLACKLIST_CRASHPAD_HELPER_H_ #define CHROME_ELF_CRASH_CRASH_HELPER_H_
#include <windows.h> #include <windows.h>
// Keep all crash-related APIs here. All other chrome_elf code should call here
// for crash support.
namespace elf_crash {
// Init the crash handling system for entire process.
bool InitializeCrashReporting();
// Any late cleanup of the crash handling system.
void ShutdownCrashReporting();
// Permanently disables subsequent calls to
// kernel32!SetUnhandledExceptionFilter(), see comment in .cc for why this is
// needed.
void DisableSetUnhandledExceptionFilter();
// Exception handler for exceptions in chrome_elf which need to be passed on to // Exception handler for exceptions in chrome_elf which need to be passed on to
// the next handler in the chain. Examples include exceptions in DllMain, // the next handler in the chain. Examples include exceptions in DllMain,
// blacklist interception code, etc. // blacklist interception code, etc.
// Note: the handler takes a minidump.
int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers); int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers);
}
#endif // CHROME_ELF_BLACKLIST_CRASHPAD_HELPER_H_ #endif // CHROME_ELF_CRASH_CRASH_HELPER_H_
...@@ -144,7 +144,9 @@ TEST_F(ELFImportsTest, DISABLED_ChromeElfLoadSanityTestImpl) { ...@@ -144,7 +144,9 @@ TEST_F(ELFImportsTest, DISABLED_ChromeElfLoadSanityTestImpl) {
// We don't expect user32 to be loaded in chrome_elf_unittests. If this test // We don't expect user32 to be loaded in chrome_elf_unittests. If this test
// case fails, then it means that a dependency on user32 has crept into the // case fails, then it means that a dependency on user32 has crept into the
// chrome_elf_unittests executable, which needs to be removed. // chrome_elf_unittests executable, which needs to be removed.
EXPECT_EQ(nullptr, ::GetModuleHandle(L"user32.dll")); // NOTE: it may be a secondary dependency of another system DLL. If so,
// try adding a "/DELAYLOAD:<blah>.dll" to the build.gn file.
ASSERT_EQ(nullptr, ::GetModuleHandle(L"user32.dll"));
HMODULE chrome_elf_module_handle = ::LoadLibrary(dll.value().c_str()); HMODULE chrome_elf_module_handle = ::LoadLibrary(dll.value().c_str());
EXPECT_TRUE(chrome_elf_module_handle != nullptr); EXPECT_TRUE(chrome_elf_module_handle != nullptr);
......
This diff is collapsed.
// 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_HOOK_UTIL_THUNK_GETTER_H_
#define CHROME_ELF_HOOK_UTIL_THUNK_GETTER_H_
#include <windows.h>
#include "base/macros.h"
namespace sandbox {
class ServiceResolverThunk;
}
namespace elf_hook {
//------------------------------------------------------------------------------
// System Service hooking support
//------------------------------------------------------------------------------
// Creates a |ServiceResolverThunk| based on the OS version. Ownership of the
// resulting thunk is passed to the caller.
sandbox::ServiceResolverThunk* HookSystemService(bool relaxed);
//------------------------------------------------------------------------------
// Import Address Table hooking support
//------------------------------------------------------------------------------
class IATHook {
public:
IATHook();
~IATHook();
// Intercept a function in an import table of a specific
// module. Saves everything needed to Unhook.
//
// NOTE: Hook can only be called once at a time, to enable Unhook().
//
// Arguments:
// module Module to be intercepted
// imported_from_module Module that exports the 'function_name'
// function_name Name of the API to be intercepted
// new_function New function pointer
//
// Returns: Windows error code (winerror.h). NO_ERROR if successful.
DWORD Hook(HMODULE module,
const char* imported_from_module,
const char* function_name,
void* new_function);
// Unhook the IAT entry.
//
// Returns: Windows error code (winerror.h). NO_ERROR if successful.
DWORD Unhook();
private:
void* intercept_function_;
void* original_function_;
IMAGE_THUNK_DATA* iat_thunk_;
DISALLOW_COPY_AND_ASSIGN(IATHook);
};
} // namespace elf_hook
#endif // CHROME_ELF_HOOK_UTIL_THUNK_GETTER_H_
// Copyright 2016 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/hook_util/hook_util.h"
// Compile in this test DLL, so that it's in the IAT.
#include "chrome_elf/hook_util/test/hook_util_test_dll.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// IATHook test constants.
const char kIATTestDllName[] = "hook_util_test_dll.dll";
const char kIATExportedApiFunction[] = "ExportedApi";
// IATHook function, which does nothing.
void IATHookedExportedApi() {
return;
}
// Shady third-party IATHook function, which also does nothing, but different
// chunk of code/address.
void IATHookedExportedApiTwo() {
printf("Something to make this function different!\n");
return;
}
class HookTest : public testing::Test {
protected:
HookTest() {}
};
//------------------------------------------------------------------------------
// IATHook tests
//------------------------------------------------------------------------------
TEST_F(HookTest, IATHook) {
// Sanity test with no hook.
ASSERT_EQ(0, ExportedApiCallCount());
ExportedApi();
ExportedApi();
ASSERT_EQ(2, ExportedApiCallCount());
// Apply IAT hook.
elf_hook::IATHook iat_hook;
if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName,
kIATExportedApiFunction,
IATHookedExportedApi) != NO_ERROR) {
ADD_FAILURE();
return;
}
// Make sure hooking twice with the same object fails.
if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName,
kIATExportedApiFunction,
IATHookedExportedApi) != ERROR_SHARING_VIOLATION)
ADD_FAILURE();
// Call count should not change with hook.
ExportedApi();
ExportedApi();
ExportedApi();
EXPECT_EQ(2, ExportedApiCallCount());
// Remove hook.
if (iat_hook.Unhook() != NO_ERROR)
ADD_FAILURE();
// Sanity test things are back to normal.
ExportedApi();
EXPECT_EQ(3, ExportedApiCallCount());
// Double unhook should fail.
if (iat_hook.Unhook() != ERROR_INVALID_PARAMETER)
ADD_FAILURE();
// Try hooking a non-existent function.
if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName, "FooBarred",
IATHookedExportedApi) != ERROR_PROC_NOT_FOUND)
ADD_FAILURE();
// Test the case where someone else hooks our hook! Unhook() should leave it.
if (iat_hook.Hook(::GetModuleHandle(nullptr), kIATTestDllName,
kIATExportedApiFunction,
IATHookedExportedApi) != NO_ERROR) {
ADD_FAILURE();
return;
}
elf_hook::IATHook shady_third_party_iat_hook;
if (shady_third_party_iat_hook.Hook(::GetModuleHandle(nullptr),
kIATTestDllName, kIATExportedApiFunction,
IATHookedExportedApiTwo) != NO_ERROR)
ADD_FAILURE();
if (iat_hook.Unhook() != ERROR_INVALID_FUNCTION)
ADD_FAILURE();
if (shady_third_party_iat_hook.Unhook() != NO_ERROR)
ADD_FAILURE();
// NOTE: the first hook was left in and couldn't be cleaned up.
}
} // namespace
// Copyright 2016 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/hook_util/test/hook_util_test_dll.h"
namespace {
int g_export_call_count = 0;
} // namespace
extern "C" __declspec(dllexport) void ExportedApi() {
g_export_call_count++;
}
extern "C" __declspec(dllexport) int ExportedApiCallCount() {
return g_export_call_count;
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
return TRUE;
}
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome_elf/blacklist/crashpad_helper.h" #ifndef CHROME_ELF_HOOK_UTIL_TEST_HOOK_UTIL_TEST_DLL_H_
#define CHROME_ELF_HOOK_UTIL_TEST_HOOK_UTIL_TEST_DLL_H_
#include "third_party/crashpad/crashpad/client/crashpad_client.h" #include <windows.h>
int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers) { extern "C" __declspec(dllexport) void ExportedApi();
crashpad::CrashpadClient::DumpWithoutCrash(
*(exception_pointers->ContextRecord)); extern "C" __declspec(dllexport) int ExportedApiCallCount();
return EXCEPTION_CONTINUE_SEARCH;
} #endif // CHROME_ELF_HOOK_UTIL_TEST_HOOK_UTIL_TEST_DLL_H_
// 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 "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_WIN10,
VERSION_WIN_LAST, // Indicates error condition.
};
#if !defined(_WIN64)
// 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;
}
#endif // !defined(_WIN64)
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 == 10) {
version_ = VERSION_WIN10;
} 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_WIN10)
thunk = new sandbox::Wow64W10ResolverThunk(current_process, relaxed);
else 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;
}
// 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_HOOK_UTIL_THUNK_GETTER_H_
#define CHROME_ELF_HOOK_UTIL_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_HOOK_UTIL_THUNK_GETTER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment