Linux: Migrate from breakpad to crashpad (see issue #3249)

Renderer process crashes are currently only reported with `--no-sandbox`.
This commit is contained in:
Marshall Greenblatt
2022-03-15 15:42:15 -04:00
parent 8fc6aced6c
commit c38d62b233
12 changed files with 187 additions and 272 deletions

View File

@@ -143,17 +143,14 @@
#include "ui/base/ui_base_switches.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
#include "base/debug/leak_annotations.h"
#include "chrome/common/chrome_paths.h"
#include "components/crash/content/browser/crash_handler_host_linux.h"
#include "components/crash/core/app/breakpad_linux.h"
#include "content/public/common/content_descriptors.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "net/ssl/client_cert_store_mac.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
#elif BUILDFLAG(IS_POSIX)
#include "components/crash/core/app/crash_switches.h"
#include "components/crash/core/app/crashpad.h"
#include "content/public/common/content_descriptors.h"
#include "libcef/common/crash_reporting.h"
#endif
#if BUILDFLAG(IS_WIN)
@@ -409,59 +406,13 @@ class CefQuotaPermissionContext : public content::QuotaPermissionContext {
};
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
const std::string& process_type) {
base::FilePath dumps_path;
base::PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
{
ANNOTATE_SCOPED_MEMORY_LEAK;
// Uploads will only occur if a non-empty crash URL is specified in
// AlloyMainDelegate::InitCrashReporter.
breakpad::CrashHandlerHostLinux* crash_handler =
new breakpad::CrashHandlerHostLinux(process_type, dumps_path,
true /* upload */);
crash_handler->StartUploaderThread();
return crash_handler;
}
}
int GetCrashSignalFD(const base::CommandLine& command_line) {
if (!breakpad::IsCrashReporterEnabled())
int GetCrashSignalFD() {
if (!crash_reporting::Enabled())
return -1;
// Extensions have the same process type as renderers.
if (command_line.HasSwitch(extensions::switches::kExtensionProcess)) {
static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost("extension");
return crash_handler->GetDeathSignalSocket();
}
std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
if (process_type == switches::kRendererProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost(process_type);
return crash_handler->GetDeathSignalSocket();
}
if (process_type == switches::kPpapiPluginProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost(process_type);
return crash_handler->GetDeathSignalSocket();
}
if (process_type == switches::kGpuProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler = nullptr;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost(process_type);
return crash_handler->GetDeathSignalSocket();
}
return -1;
int fd;
pid_t pid;
return crash_reporter::GetHandlerSocket(&fd, &pid) ? fd : -1;
}
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
@@ -797,7 +748,7 @@ void AlloyContentBrowserClient::AppendExtraCommandLineSwitches(
command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
}
#if BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
if (process_type == switches::kZygoteProcess) {
if (browser_cmd->HasSwitch(switches::kBrowserSubprocessPath)) {
// Force use of the sub-process executable path for the zygote process.
@@ -815,7 +766,17 @@ void AlloyContentBrowserClient::AppendExtraCommandLineSwitches(
command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
base::size(kSwitchNames));
}
#endif // BUILDFLAG(IS_LINUX)
if (crash_reporting::Enabled()) {
int fd;
pid_t pid;
if (crash_reporter::GetHandlerSocket(&fd, &pid)) {
command_line->AppendSwitchASCII(
crash_reporter::switches::kCrashpadHandlerPid,
base::NumberToString(pid));
}
}
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
if (app.get()) {
@@ -1132,17 +1093,17 @@ AlloyContentBrowserClient::WillCreateURLLoaderRequestInterceptors(
return interceptors;
}
#if BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
void AlloyContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
content::PosixFileDescriptorInfo* mappings) {
int crash_signal_fd = GetCrashSignalFD(command_line);
int crash_signal_fd = GetCrashSignalFD();
if (crash_signal_fd >= 0) {
mappings->Share(kCrashDumpSignal, crash_signal_fd);
}
}
#endif // BUILDFLAG(IS_LINUX)
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
void AlloyContentBrowserClient::ExposeInterfacesToRenderer(
service_manager::BinderRegistry* registry,

View File

@@ -137,7 +137,7 @@ class AlloyContentBrowserClient : public content::ContentBrowserClient {
const scoped_refptr<network::SharedURLLoaderFactory>&
network_loader_factory) override;
#if BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
void GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,

View File

@@ -21,12 +21,14 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "components/crash/core/app/crash_switches.h"
#include "content/app/content_main_runner_impl.h"
#include "content/browser/scheduler/browser_task_executor.h"
#include "content/public/app/content_main.h"
#include "content/public/app/content_main_runner.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h"
#include "third_party/crashpad/crashpad/handler/handler_main.h"
#if BUILDFLAG(IS_WIN)
#include <Objbase.h>
@@ -35,11 +37,6 @@
#include "sandbox/win/src/sandbox_types.h"
#endif
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#include "components/crash/core/app/crash_switches.h"
#include "third_party/crashpad/crashpad/handler/handler_main.h"
#endif
namespace {
enum class RuntimeType {
@@ -65,16 +62,14 @@ std::unique_ptr<CefMainRunnerDelegate> MakeDelegate(
}
}
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
// 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 both
// Windows and macOS so we define the function here instead of using the
// existing target (because we can't use that target on macOS).
// 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 =
@@ -88,8 +83,8 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) {
}),
argv.end());
#if BUILDFLAG(IS_MAC)
// HandlerMain on macOS uses the system version of getopt_long which expects
#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
@@ -111,8 +106,6 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) {
argv_as_utf8.get(), nullptr);
}
#endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
} // namespace
// Used to run the UI on a separate thread.
@@ -327,13 +320,11 @@ int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
int result;
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
if (process_type == crash_reporter::switches::kCrashpadHandler) {
result = RunAsCrashpadHandler(command_line);
main_delegate->AfterExecuteProcess();
return result;
}
#endif
// Execute the secondary process.
content::ContentMainParams main_params(

View File

@@ -52,6 +52,8 @@
#if BUILDFLAG(IS_MAC)
#include "libcef/common/util_mac.h"
#elif BUILDFLAG(IS_POSIX)
#include "libcef/common/util_linux.h"
#endif
#if BUILDFLAG(IS_WIN)
@@ -94,8 +96,7 @@ bool AlloyMainDelegate::BasicStartupComplete(int* exit_code) {
command_line->GetSwitchValueASCII(switches::kProcessType);
#if BUILDFLAG(IS_POSIX)
// Read the crash configuration file. Platforms using Breakpad also add a
// command-line switch. On Windows this is done from chrome_elf.
// Read the crash configuration file. On Windows this is done from chrome_elf.
crash_reporting::BasicStartupComplete(command_line);
#endif
@@ -355,6 +356,8 @@ void AlloyMainDelegate::PreSandboxStartup() {
// Only override these paths when executing the main process.
#if BUILDFLAG(IS_MAC)
util_mac::PreSandboxStartup();
#elif BUILDFLAG(IS_POSIX)
util_linux::PreSandboxStartup();
#endif
resource_util::OverrideDefaultDownloadDir();

View File

@@ -24,6 +24,12 @@
#include "third_party/blink/public/common/switches.h"
#include "ui/base/ui_base_switches.h"
#if BUILDFLAG(IS_MAC)
#include "libcef/common/util_mac.h"
#elif BUILDFLAG(IS_POSIX)
#include "libcef/common/util_linux.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "libcef/common/util_mac.h"
#endif
@@ -58,8 +64,7 @@ bool ChromeMainDelegateCef::BasicStartupComplete(int* exit_code) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
#if BUILDFLAG(IS_POSIX)
// Read the crash configuration file. Platforms using Breakpad also add a
// command-line switch. On Windows this is done from chrome_elf.
// Read the crash configuration file. On Windows this is done from chrome_elf.
crash_reporting::BasicStartupComplete(command_line);
#endif
@@ -143,11 +148,13 @@ void ChromeMainDelegateCef::PreSandboxStartup() {
const std::string& process_type =
command_line->GetSwitchValueASCII(switches::kProcessType);
#if BUILDFLAG(IS_MAC)
if (process_type.empty()) {
#if BUILDFLAG(IS_MAC)
util_mac::PreSandboxStartup();
#elif BUILDFLAG(IS_POSIX)
util_linux::PreSandboxStartup();
#endif
}
#endif // BUILDFLAG(IS_MAC)
// Since this may be configured via CefSettings we override the value on
// all platforms. We can't use the default implementation on macOS because

View File

@@ -615,22 +615,6 @@ void CefCrashReporterClient::GetProductNameAndVersion(std::string* product_name,
*version = product_version_;
}
#if !BUILDFLAG(IS_MAC)
base::FilePath CefCrashReporterClient::GetReporterLogFilename() {
return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
}
bool CefCrashReporterClient::EnableBreakpadForProcess(
const std::string& process_type) {
return process_type == switches::kRendererProcess ||
process_type == switches::kPpapiPluginProcess ||
process_type == switches::kZygoteProcess ||
process_type == switches::kGpuProcess;
}
#endif // !BUILDFLAG(IS_MAC)
bool CefCrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
// By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
// location to write breakpad crash dumps can be set.
@@ -654,21 +638,11 @@ bool CefCrashReporterClient::GetCollectStatsInSample() {
return true;
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
bool CefCrashReporterClient::ReportingIsEnforcedByPolicy(
bool* crashpad_enabled) {
*crashpad_enabled = true;
return true;
}
#endif
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
bool CefCrashReporterClient::IsRunningUnattended() {
// Crash upload will only be enabled with Breakpad on Linux if this method
// returns false.
return false;
}
#endif
std::string CefCrashReporterClient::GetUploadUrl() {
return server_url_;
@@ -721,13 +695,6 @@ bool CefCrashReporterClient::EnableBrowserCrashForwarding() {
}
#endif
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
CefCrashReporterClient::ParameterMap CefCrashReporterClient::FilterParameters(
const ParameterMap& parameters) {
return crash_report_utils::FilterParameters(parameters);
}
#endif
// The new Crashpad Annotation API requires that annotations be declared using
// static storage. We work around this limitation by defining a fixed amount of
// storage for each key size and later substituting the actual key name during

View File

@@ -57,23 +57,13 @@ class CefCrashReporterClient : public crash_reporter::CrashReporterClient {
void GetProductNameAndVersion(std::string* product_name,
std::string* version,
std::string* channel) override;
#if !BUILDFLAG(IS_MAC)
base::FilePath GetReporterLogFilename() override;
bool EnableBreakpadForProcess(const std::string& process_type) override;
#endif
bool GetCrashDumpLocation(base::FilePath* crash_dir) override;
#endif // BUILDFLAG(IS_POSIX)
// All of these methods must return true to enable crash report upload.
bool GetCollectStatsConsent() override;
bool GetCollectStatsInSample() override;
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
bool ReportingIsEnforcedByPolicy(bool* crashpad_enabled) override;
#endif
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
bool IsRunningUnattended() override;
#endif
std::string GetUploadUrl() override;
void GetCrashOptionalArguments(std::vector<std::string>* arguments) override;
@@ -87,10 +77,6 @@ class CefCrashReporterClient : public crash_reporter::CrashReporterClient {
bool EnableBrowserCrashForwarding() override;
#endif
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
ParameterMap FilterParameters(const ParameterMap& parameters) override;
#endif
// Set or clear a crash key value.
bool SetCrashKeyValue(const base::StringPiece& key,
const base::StringPiece& value);

View File

@@ -22,21 +22,16 @@
#if BUILDFLAG(IS_MAC)
#include "base/mac/foundation_util.h"
#include "components/crash/core/app/crashpad.h"
#include "components/crash/core/common/crash_keys.h"
#include "content/public/common/content_paths.h"
#endif
#if BUILDFLAG(IS_POSIX)
#include "base/lazy_instance.h"
#include "components/crash/core/app/crashpad.h"
#include "libcef/common/crash_reporter_client.h"
#endif
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
#include "components/crash/core/app/breakpad_linux.h"
#include "v8/include/v8-wasm-trap-handler-posix.h"
#endif
namespace crash_reporting {
namespace {
@@ -131,11 +126,10 @@ void InitCrashReporter(const base::CommandLine& command_line,
g_crash_reporting_enabled = true;
#else // !BUILDFLAG(IS_MAC)
if (process_type != switches::kZygoteProcess) {
// Crash reporting for subprocesses created using the zygote will be
// initialized in ZygoteForked.
breakpad::InitCrashReporter(process_type);
crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
g_crash_reporting_enabled = true;
}
@@ -196,10 +190,8 @@ void BasicStartupComplete(base::CommandLine* command_line) {
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
if (crash_client->ReadCrashConfigFile()) {
#if !BUILDFLAG(IS_MAC)
// Breakpad requires this switch.
command_line->AppendSwitch(switches::kEnableCrashReporter);
breakpad::SetFirstChanceExceptionHandler(v8::TryHandleWebAssemblyTrapPosix);
// Crashpad requires this switch on Linux.
command_line->AppendSwitch(switches::kEnableCrashpad);
#endif
}
}
@@ -232,8 +224,8 @@ void ZygoteForked(base::CommandLine* command_line,
const std::string& process_type) {
CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
if (crash_client->HasCrashConfigFile()) {
// Breakpad requires this switch.
command_line->AppendSwitch(switches::kEnableCrashReporter);
// Crashpad requires this switch on Linux.
command_line->AppendSwitch(switches::kEnableCrashpad);
}
InitCrashReporter(*command_line, process_type);

View File

@@ -0,0 +1,34 @@
// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
// 2011 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 "libcef/common/util_linux.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
namespace util_linux {
namespace {
void OverrideChildProcessPath() {
base::FilePath child_process_path =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kBrowserSubprocessPath);
if (child_process_path.empty())
return;
// Used by ChildProcessHost::GetChildPath and PlatformCrashpadInitialization.
base::PathService::Override(content::CHILD_PROCESS_EXE, child_process_path);
}
} // namespace
void PreSandboxStartup() {
OverrideChildProcessPath();
}
} // namespace util_linux

View File

@@ -0,0 +1,16 @@
// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
// 2011 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_COMMON_UTIL_LINUX_H_
#define CEF_LIBCEF_COMMON_UTIL_LINUX_H_
#pragma once
namespace util_linux {
// Called from MainDelegate::PreSandboxStartup for the main process.
void PreSandboxStartup();
} // namespace util_linux
#endif // CEF_LIBCEF_COMMON_UTIL_LINUX_H_