mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
bootstrap: Initialize crash reporting (see #3935)
This adds a runtime dependency on chrome_elf.dll and makes all runtime errors LOG(FATAL) to generate a crash report. Don't wait for libcef to load before running as the crashpad-handler process.
This commit is contained in:
11
BUILD.gn
11
BUILD.gn
@@ -558,6 +558,8 @@ source_set("libcef_static") {
|
|||||||
"libcef/browser/context.h",
|
"libcef/browser/context.h",
|
||||||
"libcef/browser/context_menu_params_impl.cc",
|
"libcef/browser/context_menu_params_impl.cc",
|
||||||
"libcef/browser/context_menu_params_impl.h",
|
"libcef/browser/context_menu_params_impl.h",
|
||||||
|
"libcef/browser/crashpad_runner.cc",
|
||||||
|
"libcef/browser/crashpad_runner.h",
|
||||||
"libcef/browser/devtools/devtools_controller.cc",
|
"libcef/browser/devtools/devtools_controller.cc",
|
||||||
"libcef/browser/devtools/devtools_controller.h",
|
"libcef/browser/devtools/devtools_controller.h",
|
||||||
"libcef/browser/devtools/devtools_protocol_manager.cc",
|
"libcef/browser/devtools/devtools_protocol_manager.cc",
|
||||||
@@ -1267,7 +1269,13 @@ if (is_win) {
|
|||||||
"libcef_dll/bootstrap/win/resource.h",
|
"libcef_dll/bootstrap/win/resource.h",
|
||||||
"libcef_dll/wrapper/cef_certificate_util_win.cc",
|
"libcef_dll/wrapper/cef_certificate_util_win.cc",
|
||||||
"libcef_dll/wrapper/cef_util_win.cc",
|
"libcef_dll/wrapper/cef_util_win.cc",
|
||||||
|
"libcef/browser/crashpad_runner.cc",
|
||||||
|
"libcef/browser/crashpad_runner.h",
|
||||||
"libcef/browser/preferred_stack_size_win.inc",
|
"libcef/browser/preferred_stack_size_win.inc",
|
||||||
|
"//chrome/app/delay_load_failure_hook_win.cc",
|
||||||
|
"//chrome/app/delay_load_failure_hook_win.h",
|
||||||
|
"//chrome/common/win/delay_load_failure_support.cc",
|
||||||
|
"//chrome/common/win/delay_load_failure_support.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
bootstrap_deps = [
|
bootstrap_deps = [
|
||||||
@@ -1275,6 +1283,9 @@ if (is_win) {
|
|||||||
":make_version_header",
|
":make_version_header",
|
||||||
"//base",
|
"//base",
|
||||||
"//build/win:default_exe_manifest",
|
"//build/win:default_exe_manifest",
|
||||||
|
"//chrome/install_static:secondary_module",
|
||||||
|
"//chrome/chrome_elf",
|
||||||
|
"//third_party/crashpad/crashpad/handler",
|
||||||
]
|
]
|
||||||
|
|
||||||
bootstrap_libs = [
|
bootstrap_libs = [
|
||||||
|
55
libcef/browser/crashpad_runner.cc
Normal file
55
libcef/browser/crashpad_runner.cc
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Copyright 2020 The Chromium Embedded Framework Authors.
|
||||||
|
// Portions 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 "cef/libcef/browser/crashpad_runner.h"
|
||||||
|
|
||||||
|
#include "base/command_line.h"
|
||||||
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/strings/string_util.h"
|
||||||
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "third_party/crashpad/crashpad/handler/handler_main.h"
|
||||||
|
|
||||||
|
namespace crashpad_runner {
|
||||||
|
|
||||||
|
// Based on components/crash/core/app/run_as_crashpad_handler_win.cc
|
||||||
|
int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
||||||
|
// Remove the "--type=crashpad-handler" command-line flag that will otherwise
|
||||||
|
// confuse the crashpad handler.
|
||||||
|
base::CommandLine::StringVector argv = command_line.argv();
|
||||||
|
const base::CommandLine::StringType process_type =
|
||||||
|
FILE_PATH_LITERAL("--type=");
|
||||||
|
argv.erase(
|
||||||
|
std::remove_if(argv.begin(), argv.end(),
|
||||||
|
[&process_type](const base::CommandLine::StringType& str) {
|
||||||
|
return base::StartsWith(str, process_type,
|
||||||
|
base::CompareCase::SENSITIVE) ||
|
||||||
|
(!str.empty() && str[0] == L'/');
|
||||||
|
}),
|
||||||
|
argv.end());
|
||||||
|
|
||||||
|
#if BUILDFLAG(IS_POSIX)
|
||||||
|
// HandlerMain on POSIX uses the system version of getopt_long which expects
|
||||||
|
// the first argument to be the program name.
|
||||||
|
argv.insert(argv.begin(), command_line.GetProgram().value());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<char*[]> argv_as_utf8(new char*[argv.size() + 1]);
|
||||||
|
std::vector<std::string> storage;
|
||||||
|
storage.reserve(argv.size());
|
||||||
|
for (size_t i = 0; i < argv.size(); ++i) {
|
||||||
|
#if BUILDFLAG(IS_WIN)
|
||||||
|
storage.push_back(base::WideToUTF8(argv[i]));
|
||||||
|
#else
|
||||||
|
storage.push_back(argv[i]);
|
||||||
|
#endif
|
||||||
|
argv_as_utf8[i] = &storage[i][0];
|
||||||
|
}
|
||||||
|
argv_as_utf8[argv.size()] = nullptr;
|
||||||
|
argv.clear();
|
||||||
|
return crashpad::HandlerMain(static_cast<int>(storage.size()),
|
||||||
|
argv_as_utf8.get(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad_runner
|
22
libcef/browser/crashpad_runner.h
Normal file
22
libcef/browser/crashpad_runner.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2020 The Chromium Embedded Framework Authors.
|
||||||
|
// Portions 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 CEF_LIBCEF_BROWSER_CRASHPAD_RUNNER_H_
|
||||||
|
#define CEF_LIBCEF_BROWSER_CRASHPAD_RUNNER_H_
|
||||||
|
|
||||||
|
#include "base/command_line.h"
|
||||||
|
|
||||||
|
namespace crashpad_runner {
|
||||||
|
|
||||||
|
// Chrome uses an embedded crashpad handler on Windows only and imports this
|
||||||
|
// function via the existing "run_as_crashpad_handler" target defined in
|
||||||
|
// components/crash/core/app/BUILD.gn. CEF uses an embedded handler on all
|
||||||
|
// platforms so we define the function here instead of using the existing
|
||||||
|
// target (because we can't use that target on macOS).
|
||||||
|
int RunAsCrashpadHandler(const base::CommandLine& command_line);
|
||||||
|
|
||||||
|
} // namespace crashpad_runner
|
||||||
|
|
||||||
|
#endif // CEF_LIBCEF_BROWSER_CRASHPAD_RUNNER_H_
|
@@ -13,6 +13,7 @@
|
|||||||
#include "base/synchronization/waitable_event.h"
|
#include "base/synchronization/waitable_event.h"
|
||||||
#include "cef/libcef/browser/browser_message_loop.h"
|
#include "cef/libcef/browser/browser_message_loop.h"
|
||||||
#include "cef/libcef/browser/chrome/chrome_content_browser_client_cef.h"
|
#include "cef/libcef/browser/chrome/chrome_content_browser_client_cef.h"
|
||||||
|
#include "cef/libcef/browser/crashpad_runner.h"
|
||||||
#include "cef/libcef/browser/thread_util.h"
|
#include "cef/libcef/browser/thread_util.h"
|
||||||
#include "cef/libcef/common/app_manager.h"
|
#include "cef/libcef/common/app_manager.h"
|
||||||
#include "cef/libcef/common/cef_switches.h"
|
#include "cef/libcef/common/cef_switches.h"
|
||||||
@@ -28,7 +29,6 @@
|
|||||||
#include "content/public/app/content_main.h"
|
#include "content/public/app/content_main.h"
|
||||||
#include "content/public/browser/render_process_host.h"
|
#include "content/public/browser/render_process_host.h"
|
||||||
#include "content/public/common/content_switches.h"
|
#include "content/public/common/content_switches.h"
|
||||||
#include "third_party/crashpad/crashpad/handler/handler_main.h"
|
|
||||||
|
|
||||||
#if BUILDFLAG(IS_WIN)
|
#if BUILDFLAG(IS_WIN)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -41,54 +41,6 @@
|
|||||||
#include "sandbox/win/src/sandbox_types.h"
|
#include "sandbox/win/src/sandbox_types.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Based on components/crash/core/app/run_as_crashpad_handler_win.cc
|
|
||||||
// Remove the "--type=crashpad-handler" command-line flag that will otherwise
|
|
||||||
// confuse the crashpad handler.
|
|
||||||
// Chrome uses an embedded crashpad handler on Windows only and imports this
|
|
||||||
// function via the existing "run_as_crashpad_handler" target defined in
|
|
||||||
// components/crash/core/app/BUILD.gn. CEF uses an embedded handler on all
|
|
||||||
// platforms so we define the function here instead of using the existing
|
|
||||||
// target (because we can't use that target on macOS).
|
|
||||||
int RunAsCrashpadHandler(const base::CommandLine& command_line) {
|
|
||||||
base::CommandLine::StringVector argv = command_line.argv();
|
|
||||||
const base::CommandLine::StringType process_type =
|
|
||||||
FILE_PATH_LITERAL("--type=");
|
|
||||||
argv.erase(
|
|
||||||
std::remove_if(argv.begin(), argv.end(),
|
|
||||||
[&process_type](const base::CommandLine::StringType& str) {
|
|
||||||
return base::StartsWith(str, process_type,
|
|
||||||
base::CompareCase::SENSITIVE) ||
|
|
||||||
(!str.empty() && str[0] == L'/');
|
|
||||||
}),
|
|
||||||
argv.end());
|
|
||||||
|
|
||||||
#if BUILDFLAG(IS_POSIX)
|
|
||||||
// HandlerMain on POSIX uses the system version of getopt_long which expects
|
|
||||||
// the first argument to be the program name.
|
|
||||||
argv.insert(argv.begin(), command_line.GetProgram().value());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::unique_ptr<char*[]> argv_as_utf8(new char*[argv.size() + 1]);
|
|
||||||
std::vector<std::string> storage;
|
|
||||||
storage.reserve(argv.size());
|
|
||||||
for (size_t i = 0; i < argv.size(); ++i) {
|
|
||||||
#if BUILDFLAG(IS_WIN)
|
|
||||||
storage.push_back(base::WideToUTF8(argv[i]));
|
|
||||||
#else
|
|
||||||
storage.push_back(argv[i]);
|
|
||||||
#endif
|
|
||||||
argv_as_utf8[i] = &storage[i][0];
|
|
||||||
}
|
|
||||||
argv_as_utf8[argv.size()] = nullptr;
|
|
||||||
argv.clear();
|
|
||||||
return crashpad::HandlerMain(static_cast<int>(storage.size()),
|
|
||||||
argv_as_utf8.get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
CefMainRunner::CefMainRunner(bool multi_threaded_message_loop,
|
CefMainRunner::CefMainRunner(bool multi_threaded_message_loop,
|
||||||
bool external_message_pump)
|
bool external_message_pump)
|
||||||
: multi_threaded_message_loop_(multi_threaded_message_loop),
|
: multi_threaded_message_loop_(multi_threaded_message_loop),
|
||||||
@@ -243,7 +195,7 @@ int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
|
|||||||
BeforeMainInitialize(args);
|
BeforeMainInitialize(args);
|
||||||
|
|
||||||
if (process_type == crash_reporter::switches::kCrashpadHandler) {
|
if (process_type == crash_reporter::switches::kCrashpadHandler) {
|
||||||
return RunAsCrashpadHandler(command_line);
|
return crashpad_runner::RunAsCrashpadHandler(command_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the secondary process.
|
// Execute the secondary process.
|
||||||
|
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/files/file_path.h"
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/files/file_util.h"
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/process/memory.h"
|
||||||
#include "base/process/process_info.h"
|
#include "base/process/process_info.h"
|
||||||
#include "base/strings/string_number_conversions.h"
|
#include "base/strings/string_number_conversions.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
@@ -16,12 +19,37 @@
|
|||||||
#include "cef/include/internal/cef_types.h"
|
#include "cef/include/internal/cef_types.h"
|
||||||
#include "cef/include/wrapper/cef_certificate_util_win.h"
|
#include "cef/include/wrapper/cef_certificate_util_win.h"
|
||||||
#include "cef/include/wrapper/cef_util_win.h"
|
#include "cef/include/wrapper/cef_util_win.h"
|
||||||
|
#include "cef/libcef/browser/crashpad_runner.h"
|
||||||
#include "cef/libcef/browser/preferred_stack_size_win.inc"
|
#include "cef/libcef/browser/preferred_stack_size_win.inc"
|
||||||
#include "cef/libcef_dll/bootstrap/bootstrap_util_win.h"
|
#include "cef/libcef_dll/bootstrap/bootstrap_util_win.h"
|
||||||
#include "cef/libcef_dll/bootstrap/win/resource.h"
|
#include "cef/libcef_dll/bootstrap/win/resource.h"
|
||||||
|
#include "chrome/app/delay_load_failure_hook_win.h"
|
||||||
|
#include "chrome/chrome_elf/chrome_elf_main.h"
|
||||||
|
#include "chrome/install_static/initialize_from_primary_module.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Sets the current working directory for the process to the directory holding
|
||||||
|
// the executable if this is the browser process. This avoids leaking a handle
|
||||||
|
// to an arbitrary directory to child processes (e.g., the crashpad handler
|
||||||
|
// process).
|
||||||
|
void SetCwdForBrowserProcess() {
|
||||||
|
if (!::IsBrowserProcess()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<wchar_t, MAX_PATH + 1> buffer;
|
||||||
|
buffer[0] = L'\0';
|
||||||
|
DWORD length = ::GetModuleFileName(nullptr, &buffer[0], buffer.size());
|
||||||
|
if (!length || length >= buffer.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base::SetCurrentDirectory(
|
||||||
|
base::FilePath(base::FilePath::StringViewType(&buffer[0], length))
|
||||||
|
.DirName());
|
||||||
|
}
|
||||||
|
|
||||||
// Load a string from the string table in bootstrap.rc.
|
// Load a string from the string table in bootstrap.rc.
|
||||||
std::wstring LoadString(int string_id) {
|
std::wstring LoadString(int string_id) {
|
||||||
const int kMaxSize = 100;
|
const int kMaxSize = 100;
|
||||||
@@ -53,6 +81,39 @@ void ShowError(const std::wstring& error) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring NormalizeError(const std::wstring& err) {
|
||||||
|
std::wstring str = err;
|
||||||
|
// Replace newlines.
|
||||||
|
std::replace(str.begin(), str.end(), L'\n', L' ');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify DLL code signing requirements.
|
||||||
|
void CheckDllCodeSigning(
|
||||||
|
const base::FilePath& dll_path,
|
||||||
|
const cef_certificate_util::ThumbprintsInfo& exe_thumbprints) {
|
||||||
|
cef_certificate_util::ThumbprintsInfo dll_thumbprints;
|
||||||
|
cef_certificate_util::GetClientThumbprints(
|
||||||
|
dll_path.value(), /*verify_binary=*/true, dll_thumbprints);
|
||||||
|
|
||||||
|
// The DLL and EXE must either both be unsigned or both have all valid
|
||||||
|
// signatures and the same primary thumbprint.
|
||||||
|
if (!dll_thumbprints.IsSame(exe_thumbprints, /*allow_unsigned=*/true)) {
|
||||||
|
// Some part of the certificate validation process failed.
|
||||||
|
const auto subst = std::to_array<std::u16string>(
|
||||||
|
{base::WideToUTF16(dll_path.BaseName().value()),
|
||||||
|
base::WideToUTF16(dll_thumbprints.errors)});
|
||||||
|
ShowError(FormatErrorString(IDS_ERROR_INVALID_CERT, subst));
|
||||||
|
if (dll_thumbprints.errors.empty()) {
|
||||||
|
LOG(FATAL) << "Failed " << dll_path.value()
|
||||||
|
<< " certificate requirements";
|
||||||
|
} else {
|
||||||
|
LOG(FATAL) << "Failed " << dll_path.value() << " certificate checks: "
|
||||||
|
<< NormalizeError(dll_thumbprints.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE)
|
#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE)
|
||||||
@@ -87,17 +148,37 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SetCwdForBrowserProcess();
|
||||||
|
install_static::InitializeFromPrimaryModule();
|
||||||
|
SignalInitializeCrashReporting();
|
||||||
|
if (IsBrowserProcess()) {
|
||||||
|
chrome::DisableDelayLoadFailureHooksForMainExecutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done here to ensure that OOMs that happen early in process initialization
|
||||||
|
// are correctly signaled to the OS.
|
||||||
|
base::EnableTerminationOnOutOfMemory();
|
||||||
|
logging::RegisterAbslAbortHook();
|
||||||
|
|
||||||
// Parse command-line arguments.
|
// Parse command-line arguments.
|
||||||
const base::CommandLine command_line =
|
const base::CommandLine command_line =
|
||||||
base::CommandLine::FromString(::GetCommandLineW());
|
base::CommandLine::FromString(::GetCommandLineW());
|
||||||
|
|
||||||
constexpr char kProcessType[] = "type";
|
constexpr char kProcessType[] = "type";
|
||||||
const bool is_subprocess = command_line.HasSwitch(kProcessType);
|
const bool is_subprocess = command_line.HasSwitch(kProcessType);
|
||||||
if (is_subprocess && command_line.GetSwitchValueASCII(kProcessType).empty()) {
|
const std::string& process_type =
|
||||||
|
command_line.GetSwitchValueASCII(kProcessType);
|
||||||
|
if (is_subprocess && process_type.empty()) {
|
||||||
// Early exit on invalid process type.
|
// Early exit on invalid process type.
|
||||||
return CEF_RESULT_CODE_BAD_PROCESS_TYPE;
|
return CEF_RESULT_CODE_BAD_PROCESS_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the crashpad handler now instead of waiting for libcef to load.
|
||||||
|
constexpr char kCrashpadHandler[] = "crashpad-handler";
|
||||||
|
if (process_type == kCrashpadHandler) {
|
||||||
|
return crashpad_runner::RunAsCrashpadHandler(command_line);
|
||||||
|
}
|
||||||
|
|
||||||
// True if this is a sandboxed sub-process. Uses similar logic to
|
// True if this is a sandboxed sub-process. Uses similar logic to
|
||||||
// Sandbox::IsProcessSandboxed.
|
// Sandbox::IsProcessSandboxed.
|
||||||
const bool is_sandboxed =
|
const bool is_sandboxed =
|
||||||
@@ -133,7 +214,7 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||||||
|
|
||||||
if (bootstrap_util::IsDefaultExeName(dll_name)) {
|
if (bootstrap_util::IsDefaultExeName(dll_name)) {
|
||||||
ShowError(LoadString(IDS_ERROR_NO_MODULE_NAME));
|
ShowError(LoadString(IDS_ERROR_NO_MODULE_NAME));
|
||||||
return CEF_RESULT_CODE_KILLED;
|
LOG(FATAL) << "Missing module name";
|
||||||
}
|
}
|
||||||
|
|
||||||
cef_certificate_util::GetClientThumbprints(
|
cef_certificate_util::GetClientThumbprints(
|
||||||
@@ -146,14 +227,67 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||||||
{base::WideToUTF16(exe_path.BaseName().value()),
|
{base::WideToUTF16(exe_path.BaseName().value()),
|
||||||
base::WideToUTF16(exe_thumbprints.errors)});
|
base::WideToUTF16(exe_thumbprints.errors)});
|
||||||
ShowError(FormatErrorString(IDS_ERROR_INVALID_CERT, subst));
|
ShowError(FormatErrorString(IDS_ERROR_INVALID_CERT, subst));
|
||||||
return CEF_RESULT_CODE_KILLED;
|
if (exe_thumbprints.errors.empty()) {
|
||||||
|
LOG(FATAL) << "Failed " << exe_path.value()
|
||||||
|
<< " certificate requirements";
|
||||||
|
} else {
|
||||||
|
LOG(FATAL) << "Failed " << exe_path.value() << " certificate checks: "
|
||||||
|
<< NormalizeError(exe_thumbprints.errors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manage the life span of the sandbox information object. This is necessary
|
if (!is_sandboxed) {
|
||||||
// for sandbox support on Windows. See cef_sandbox_win.h for complete details.
|
// Check chrome_elf.dll which should be preloaded to support crash
|
||||||
CefScopedSandboxInfo scoped_sandbox;
|
// reporting.
|
||||||
void* sandbox_info = scoped_sandbox.sandbox_info();
|
if (HMODULE hModule = ::LoadLibrary(L"chrome_elf")) {
|
||||||
|
const auto& dll_path = bootstrap_util::GetModulePath(hModule);
|
||||||
|
|
||||||
|
// Must be in the same directory as the EXE.
|
||||||
|
if (dll_path.DirName() != exe_path.DirName()) {
|
||||||
|
const auto subst = std::to_array<std::u16string>({u"chrome_elf"});
|
||||||
|
ShowError(FormatErrorString(IDS_ERROR_INVALID_LOCATION, subst));
|
||||||
|
LOG(FATAL) << "Invalid location: " << dll_path.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckDllCodeSigning(dll_path, exe_thumbprints);
|
||||||
|
|
||||||
|
FreeLibrary(hModule);
|
||||||
|
} else {
|
||||||
|
LOG(FATAL) << "Failed to load chrome_elf.dll with error "
|
||||||
|
<< ::GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the client DLL as untrusted (e.g. without executing DllMain or
|
||||||
|
// loading additional modules) so that we can first check requirements.
|
||||||
|
// LoadLibrary's "default search order" is tricky and we don't want to
|
||||||
|
// guess about what DLL it will load. DONT_RESOLVE_DLL_REFERENCES is the
|
||||||
|
// only option that doesn't execute DllMain while still allowing us
|
||||||
|
// retrieve the path using GetModuleFileName. No execution of the DLL
|
||||||
|
// should be attempted while loaded in this mode.
|
||||||
|
if (HMODULE hModule = ::LoadLibraryEx(dll_name.c_str(), nullptr,
|
||||||
|
DONT_RESOLVE_DLL_REFERENCES)) {
|
||||||
|
const auto& dll_path = bootstrap_util::GetModulePath(hModule);
|
||||||
|
|
||||||
|
if (!bootstrap_util::IsModulePathAllowed(dll_path, exe_path)) {
|
||||||
|
const auto subst =
|
||||||
|
std::to_array<std::u16string>({base::WideToUTF16(dll_name)});
|
||||||
|
ShowError(FormatErrorString(IDS_ERROR_INVALID_LOCATION, subst));
|
||||||
|
LOG(FATAL) << "Invalid location: " << dll_path.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckDllCodeSigning(dll_path, exe_thumbprints);
|
||||||
|
|
||||||
|
FreeLibrary(hModule);
|
||||||
|
} else {
|
||||||
|
const auto subst = std::to_array<std::u16string>(
|
||||||
|
{base::WideToUTF16(dll_name),
|
||||||
|
base::WideToUTF16(cef_util::GetLastErrorAsString())});
|
||||||
|
ShowError(FormatErrorString(IDS_ERROR_LOAD_FAILED, subst));
|
||||||
|
LOG(FATAL) << "Failed to load " << dll_name << ".dll with error "
|
||||||
|
<< ::GetLastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE)
|
#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE)
|
||||||
constexpr char kProcName[] = "RunConsoleMain";
|
constexpr char kProcName[] = "RunConsoleMain";
|
||||||
@@ -163,81 +297,49 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||||||
using kProcType = decltype(&RunWinMain);
|
using kProcType = decltype(&RunWinMain);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::wstring error;
|
int result_code;
|
||||||
|
|
||||||
if (!is_sandboxed) {
|
|
||||||
// Load the client DLL as untrusted (e.g. without executing DllMain or
|
|
||||||
// loading additional modules) so that we can first check requirements.
|
|
||||||
// LoadLibrary's "default search order" is tricky and we don't want to guess
|
|
||||||
// about what DLL it will load. DONT_RESOLVE_DLL_REFERENCES is the only
|
|
||||||
// option that doesn't execute DllMain while still allowing us retrieve the
|
|
||||||
// path using GetModuleFileName. No execution of the DLL should be attempted
|
|
||||||
// while loaded in this mode.
|
|
||||||
if (HMODULE hModule = ::LoadLibraryEx(dll_name.c_str(), nullptr,
|
|
||||||
DONT_RESOLVE_DLL_REFERENCES)) {
|
|
||||||
const auto& dll_path = bootstrap_util::GetModulePath(hModule);
|
|
||||||
|
|
||||||
if (!bootstrap_util::IsModulePathAllowed(dll_path, exe_path)) {
|
|
||||||
const auto subst =
|
|
||||||
std::to_array<std::u16string>({base::WideToUTF16(dll_name)});
|
|
||||||
error = FormatErrorString(IDS_ERROR_INVALID_LOCATION, subst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.empty()) {
|
|
||||||
cef_certificate_util::ThumbprintsInfo dll_thumbprints;
|
|
||||||
cef_certificate_util::GetClientThumbprints(
|
|
||||||
dll_path.value(), /*verify_binary=*/true, dll_thumbprints);
|
|
||||||
|
|
||||||
// The DLL and EXE must either both be unsigned or both have all valid
|
|
||||||
// signatures and the same primary thumbprint.
|
|
||||||
if (!dll_thumbprints.IsSame(exe_thumbprints, /*allow_unsigned=*/true)) {
|
|
||||||
// Some part of the certificate validation process failed.
|
|
||||||
const auto subst = std::to_array<std::u16string>(
|
|
||||||
{base::WideToUTF16(dll_name + TEXT(".dll")),
|
|
||||||
base::WideToUTF16(dll_thumbprints.errors)});
|
|
||||||
error = FormatErrorString(IDS_ERROR_INVALID_CERT, subst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeLibrary(hModule);
|
|
||||||
} else {
|
|
||||||
const auto subst = std::to_array<std::u16string>(
|
|
||||||
{base::WideToUTF16(dll_name),
|
|
||||||
base::WideToUTF16(cef_util::GetLastErrorAsString())});
|
|
||||||
error = FormatErrorString(IDS_ERROR_LOAD_FAILED, subst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.empty()) {
|
|
||||||
// Load the client DLL normally.
|
// Load the client DLL normally.
|
||||||
if (HMODULE hModule = ::LoadLibrary(dll_name.c_str())) {
|
if (HMODULE hModule = ::LoadLibrary(dll_name.c_str())) {
|
||||||
if (auto* pFunc = (kProcType)::GetProcAddress(hModule, kProcName)) {
|
if (auto* pFunc = (kProcType)::GetProcAddress(hModule, kProcName)) {
|
||||||
|
// Manage the life span of the sandbox information object. This is
|
||||||
|
// necessary for sandbox support on Windows. See cef_sandbox_win.h for
|
||||||
|
// complete details.
|
||||||
|
CefScopedSandboxInfo scoped_sandbox;
|
||||||
|
void* sandbox_info = scoped_sandbox.sandbox_info();
|
||||||
|
|
||||||
#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE)
|
#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE)
|
||||||
return pFunc(argc, argv, sandbox_info);
|
result_code = pFunc(argc, argv, sandbox_info);
|
||||||
#else
|
#else
|
||||||
return pFunc(hInstance, lpCmdLine, nCmdShow, sandbox_info);
|
result_code = pFunc(hInstance, lpCmdLine, nCmdShow, sandbox_info);
|
||||||
#endif
|
#endif
|
||||||
} else if (!is_sandboxed) {
|
} else {
|
||||||
|
if (!is_sandboxed) {
|
||||||
const auto subst = std::to_array<std::u16string>(
|
const auto subst = std::to_array<std::u16string>(
|
||||||
{base::WideToUTF16(dll_name),
|
{base::WideToUTF16(dll_name),
|
||||||
base::WideToUTF16(cef_util::GetLastErrorAsString()),
|
base::WideToUTF16(cef_util::GetLastErrorAsString()),
|
||||||
base::ASCIIToUTF16(std::string(kProcName))});
|
base::ASCIIToUTF16(std::string(kProcName))});
|
||||||
error = FormatErrorString(IDS_ERROR_NO_PROC_EXPORT, subst);
|
ShowError(FormatErrorString(IDS_ERROR_NO_PROC_EXPORT, subst));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(FATAL) << "Failed to find " << kProcName << " in " << dll_name
|
||||||
|
<< ".dll with error " << ::GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(hModule);
|
FreeLibrary(hModule);
|
||||||
} else if (!is_sandboxed) {
|
} else {
|
||||||
|
if (!is_sandboxed) {
|
||||||
const auto subst = std::to_array<std::u16string>(
|
const auto subst = std::to_array<std::u16string>(
|
||||||
{base::WideToUTF16(dll_name),
|
{base::WideToUTF16(dll_name),
|
||||||
base::WideToUTF16(cef_util::GetLastErrorAsString())});
|
base::WideToUTF16(cef_util::GetLastErrorAsString())});
|
||||||
error = FormatErrorString(IDS_ERROR_LOAD_FAILED, subst);
|
ShowError(FormatErrorString(IDS_ERROR_LOAD_FAILED, subst));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't try to show errors while sandboxed.
|
LOG(FATAL) << "Failed to load " << dll_name << ".dll with error "
|
||||||
if (!error.empty() && !is_sandboxed) {
|
<< ::GetLastError();
|
||||||
ShowError(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CEF_RESULT_CODE_KILLED;
|
// LOG(FATAL) is [[noreturn]], so we only reach this point if everything
|
||||||
|
// succeeded.
|
||||||
|
return result_code;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user