android/linux: add a client interface to control sanitization

Sanitization is controlled by a SanitizationInformation struct to be
read from the client's memory. The address of this struct is either
passed in a ClientInformation when the client requests a crash dump,
or as a flag to the handler --sanitization_information.

Bug: crashpad:30
Change-Id: I2744f8fb85b4fea7362b2b88faa4bef1da74e36b
Reviewed-on: https://chromium-review.googlesource.com/1083143
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Joshua Peraza 2018-06-12 08:30:36 -07:00 committed by Commit Bot
parent a42b5269b4
commit d1e6a2130d
18 changed files with 385 additions and 47 deletions

View File

@ -28,6 +28,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "snapshot/annotation_snapshot.h" #include "snapshot/annotation_snapshot.h"
#include "snapshot/minidump/process_snapshot_minidump.h" #include "snapshot/minidump/process_snapshot_minidump.h"
#include "snapshot/sanitized/sanitization_information.h"
#include "test/multiprocess.h" #include "test/multiprocess.h"
#include "test/multiprocess_exec.h" #include "test/multiprocess_exec.h"
#include "test/scoped_temp_dir.h" #include "test/scoped_temp_dir.h"
@ -210,7 +211,9 @@ class StartHandlerForClientTest {
StartHandlerForClientTest() = default; StartHandlerForClientTest() = default;
~StartHandlerForClientTest() = default; ~StartHandlerForClientTest() = default;
bool Initialize() { bool Initialize(bool sanitize) {
sanitize_ = sanitize;
int socks[2]; int socks[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) {
PLOG(ERROR) << "socketpair"; PLOG(ERROR) << "socketpair";
@ -253,19 +256,23 @@ class StartHandlerForClientTest {
ASSERT_TRUE(database); ASSERT_TRUE(database);
std::vector<CrashReportDatabase::Report> reports; std::vector<CrashReportDatabase::Report> reports;
ASSERT_EQ(database->GetPendingReports(&reports),
CrashReportDatabase::kNoError);
EXPECT_EQ(reports.size(), 1u);
reports.clear();
ASSERT_EQ(database->GetCompletedReports(&reports), ASSERT_EQ(database->GetCompletedReports(&reports),
CrashReportDatabase::kNoError); CrashReportDatabase::kNoError);
EXPECT_EQ(reports.size(), 0u); EXPECT_EQ(reports.size(), 0u);
reports.clear();
ASSERT_EQ(database->GetPendingReports(&reports),
CrashReportDatabase::kNoError);
if (sanitize_) {
EXPECT_EQ(reports.size(), 0u);
} else {
EXPECT_EQ(reports.size(), 1u);
}
} }
bool InstallHandler() { bool InstallHandler() {
auto signal_handler = SandboxedHandler::Get(); auto signal_handler = SandboxedHandler::Get();
return signal_handler->Initialize(client_sock_.get()); return signal_handler->Initialize(client_sock_.get(), sanitize_);
} }
private: private:
@ -278,8 +285,9 @@ class StartHandlerForClientTest {
return instance; return instance;
} }
bool Initialize(FileHandle client_sock) { bool Initialize(FileHandle client_sock, bool sanitize) {
client_sock_ = client_sock; client_sock_ = client_sock;
sanitize_ = sanitize;
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr); return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
} }
@ -302,11 +310,20 @@ class StartHandlerForClientTest {
context); context);
exception_information.thread_id = syscall(SYS_gettid); exception_information.thread_id = syscall(SYS_gettid);
ClientInformation info = {}; ClientInformation info;
info.exception_information_address = info.exception_information_address =
FromPointerCast<decltype(info.exception_information_address)>( FromPointerCast<decltype(info.exception_information_address)>(
&exception_information); &exception_information);
SanitizationInformation sanitization_info = {};
if (state->sanitize_) {
info.sanitization_information_address =
FromPointerCast<VMAddress>(&sanitization_info);
// Target a non-module address to prevent a crash dump.
sanitization_info.target_module_address =
FromPointerCast<VMAddress>(&sanitization_info);
}
ExceptionHandlerClient handler_client(state->client_sock_); ExceptionHandlerClient handler_client(state->client_sock_);
CHECK_EQ(handler_client.RequestCrashDump(info), 0); CHECK_EQ(handler_client.RequestCrashDump(info), 0);
@ -314,6 +331,7 @@ class StartHandlerForClientTest {
} }
FileHandle client_sock_; FileHandle client_sock_;
bool sanitize_;
DISALLOW_COPY_AND_ASSIGN(SandboxedHandler); DISALLOW_COPY_AND_ASSIGN(SandboxedHandler);
}; };
@ -321,6 +339,7 @@ class StartHandlerForClientTest {
ScopedTempDir temp_dir_; ScopedTempDir temp_dir_;
ScopedFileHandle client_sock_; ScopedFileHandle client_sock_;
ScopedFileHandle server_sock_; ScopedFileHandle server_sock_;
bool sanitize_;
DISALLOW_COPY_AND_ASSIGN(StartHandlerForClientTest); DISALLOW_COPY_AND_ASSIGN(StartHandlerForClientTest);
}; };
@ -331,9 +350,9 @@ class StartHandlerForChildTest : public Multiprocess {
StartHandlerForChildTest() = default; StartHandlerForChildTest() = default;
~StartHandlerForChildTest() = default; ~StartHandlerForChildTest() = default;
bool Initialize() { bool Initialize(bool sanitize) {
SetExpectedChildTerminationBuiltinTrap(); SetExpectedChildTerminationBuiltinTrap();
return test_state_.Initialize(); return test_state_.Initialize(sanitize);
} }
private: private:
@ -361,7 +380,13 @@ class StartHandlerForChildTest : public Multiprocess {
TEST(CrashpadClient, StartHandlerForChild) { TEST(CrashpadClient, StartHandlerForChild) {
StartHandlerForChildTest test; StartHandlerForChildTest test;
ASSERT_TRUE(test.Initialize()); ASSERT_TRUE(test.Initialize(/* sanitize= */ false));
test.Run();
}
TEST(CrashpadClient, SanitizedChild) {
StartHandlerForChildTest test;
ASSERT_TRUE(test.Initialize(/* sanitize= */ true));
test.Run(); test.Run();
} }

View File

@ -144,6 +144,8 @@ void Usage(const base::FilePath& me) {
" --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n" " --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n"
" request a dump for the handler's parent process\n" " request a dump for the handler's parent process\n"
" --initial-client-fd=FD a socket connected to a client.\n" " --initial-client-fd=FD a socket connected to a client.\n"
" --sanitization_information=SANITIZATION_INFORMATION_ADDRESS\n"
" the address of a SanitizationInformation struct.\n"
#endif // OS_LINUX || OS_ANDROID #endif // OS_LINUX || OS_ANDROID
" --url=URL send crash reports to this Breakpad server URL,\n" " --url=URL send crash reports to this Breakpad server URL,\n"
" only if uploads are enabled for the database\n" " only if uploads are enabled for the database\n"
@ -167,6 +169,7 @@ struct Options {
#elif defined(OS_LINUX) || defined(OS_ANDROID) #elif defined(OS_LINUX) || defined(OS_ANDROID)
VMAddress exception_information_address; VMAddress exception_information_address;
int initial_client_fd; int initial_client_fd;
VMAddress sanitization_information_address;
#elif defined(OS_WIN) #elif defined(OS_WIN)
std::string pipe_name; std::string pipe_name;
InitialClientData initial_client_data; InitialClientData initial_client_data;
@ -535,6 +538,7 @@ int HandlerMain(int argc,
#if defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_ANDROID)
kOptionTraceParentWithException, kOptionTraceParentWithException,
kOptionInitialClientFD, kOptionInitialClientFD,
kOptionSanitizationInformation,
#endif #endif
kOptionURL, kOptionURL,
@ -590,6 +594,10 @@ int HandlerMain(int argc,
nullptr, nullptr,
kOptionTraceParentWithException}, kOptionTraceParentWithException},
{"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD}, {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD},
{"sanitization-information",
required_argument,
nullptr,
kOptionSanitizationInformation},
#endif // OS_LINUX || OS_ANDROID #endif // OS_LINUX || OS_ANDROID
{"url", required_argument, nullptr, kOptionURL}, {"url", required_argument, nullptr, kOptionURL},
{"help", no_argument, nullptr, kOptionHelp}, {"help", no_argument, nullptr, kOptionHelp},
@ -608,6 +616,7 @@ int HandlerMain(int argc,
#if defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_ANDROID)
options.exception_information_address = 0; options.exception_information_address = 0;
options.initial_client_fd = kInvalidFileHandle; options.initial_client_fd = kInvalidFileHandle;
options.sanitization_information_address = 0;
#endif #endif
int opt; int opt;
@ -714,6 +723,15 @@ int HandlerMain(int argc,
} }
break; break;
} }
case kOptionSanitizationInformation: {
if (!StringToNumber(optarg,
&options.sanitization_information_address)) {
ToolSupport::UsageHint(me,
"failed to parse --sanitization-information");
return ExitFailure();
}
break;
}
#endif // OS_LINUX || OS_ANDROID #endif // OS_LINUX || OS_ANDROID
case kOptionURL: { case kOptionURL: {
options.url = optarg; options.url = optarg;
@ -762,9 +780,15 @@ int HandlerMain(int argc,
#elif defined(OS_LINUX) || defined(OS_ANDROID) #elif defined(OS_LINUX) || defined(OS_ANDROID)
if (!options.exception_information_address && if (!options.exception_information_address &&
options.initial_client_fd == kInvalidFileHandle) { options.initial_client_fd == kInvalidFileHandle) {
ToolSupport::UsageHint(
me, "--trace-parent-with-exception or --initial_client_fd is required");
return ExitFailure();
}
if (options.sanitization_information_address &&
!options.exception_information_address) {
ToolSupport::UsageHint( ToolSupport::UsageHint(
me, me,
"--exception_information_address or --initial_client_fd is required"); "--sanitization_information requires --trace-parent-with-exception");
return ExitFailure(); return ExitFailure();
} }
#endif // OS_MACOSX #endif // OS_MACOSX
@ -844,9 +868,12 @@ int HandlerMain(int argc,
#if defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_ANDROID)
if (options.exception_information_address) { if (options.exception_information_address) {
return exception_handler.HandleException(getppid(), ClientInformation info;
options.exception_information_address) ? info.exception_information_address = options.exception_information_address;
EXIT_SUCCESS : ExitFailure(); info.sanitization_information_address =
options.sanitization_information_address;
return exception_handler.HandleException(getppid(), info) ? EXIT_SUCCESS
: ExitFailure();
} }
#endif // OS_LINUX || OS_ANDROID #endif // OS_LINUX || OS_ANDROID

View File

@ -21,6 +21,8 @@
#include "minidump/minidump_file_writer.h" #include "minidump/minidump_file_writer.h"
#include "snapshot/crashpad_info_client_options.h" #include "snapshot/crashpad_info_client_options.h"
#include "snapshot/linux/process_snapshot_linux.h" #include "snapshot/linux/process_snapshot_linux.h"
#include "snapshot/sanitized/process_snapshot_sanitized.h"
#include "snapshot/sanitized/sanitization_information.h"
#include "util/linux/direct_ptrace_connection.h" #include "util/linux/direct_ptrace_connection.h"
#include "util/linux/ptrace_client.h" #include "util/linux/ptrace_client.h"
#include "util/misc/metrics.h" #include "util/misc/metrics.h"
@ -43,7 +45,7 @@ CrashReportExceptionHandler::~CrashReportExceptionHandler() = default;
bool CrashReportExceptionHandler::HandleException( bool CrashReportExceptionHandler::HandleException(
pid_t client_process_id, pid_t client_process_id,
VMAddress exception_info_address) { const ClientInformation& info) {
Metrics::ExceptionEncountered(); Metrics::ExceptionEncountered();
DirectPtraceConnection connection; DirectPtraceConnection connection;
@ -53,12 +55,12 @@ bool CrashReportExceptionHandler::HandleException(
return false; return false;
} }
return HandleExceptionWithConnection(&connection, exception_info_address); return HandleExceptionWithConnection(&connection, info);
} }
bool CrashReportExceptionHandler::HandleExceptionWithBroker( bool CrashReportExceptionHandler::HandleExceptionWithBroker(
pid_t client_process_id, pid_t client_process_id,
VMAddress exception_info_address, const ClientInformation& info,
int broker_sock) { int broker_sock) {
Metrics::ExceptionEncountered(); Metrics::ExceptionEncountered();
@ -69,19 +71,20 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker(
return false; return false;
} }
return HandleExceptionWithConnection(&client, exception_info_address); return HandleExceptionWithConnection(&client, info);
} }
bool CrashReportExceptionHandler::HandleExceptionWithConnection( bool CrashReportExceptionHandler::HandleExceptionWithConnection(
PtraceConnection* connection, PtraceConnection* connection,
VMAddress exception_info_address) { const ClientInformation& info) {
ProcessSnapshotLinux process_snapshot; ProcessSnapshotLinux process_snapshot;
if (!process_snapshot.Initialize(connection)) { if (!process_snapshot.Initialize(connection)) {
Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed);
return false; return false;
} }
if (!process_snapshot.InitializeException(exception_info_address)) { if (!process_snapshot.InitializeException(
info.exception_information_address)) {
Metrics::ExceptionCaptureResult( Metrics::ExceptionCaptureResult(
Metrics::CaptureResult::kExceptionInitializationFailed); Metrics::CaptureResult::kExceptionInitializationFailed);
return false; return false;
@ -116,10 +119,50 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection(
process_snapshot.SetReportID(new_report->ReportID()); process_snapshot.SetReportID(new_report->ReportID());
ProcessSnapshot* snapshot = nullptr;
ProcessSnapshotSanitized sanitized;
std::vector<std::string> whitelist;
if (info.sanitization_information_address) {
SanitizationInformation sanitization_info;
ProcessMemoryRange range;
if (!range.Initialize(connection->Memory(), connection->Is64Bit()) ||
!range.Read(info.sanitization_information_address,
sizeof(sanitization_info),
&sanitization_info)) {
Metrics::ExceptionCaptureResult(
Metrics::CaptureResult::kSanitizationInitializationFailed);
return false;
}
if (sanitization_info.annotations_whitelist_address &&
!ReadAnnotationsWhitelist(
range,
sanitization_info.annotations_whitelist_address,
&whitelist)) {
Metrics::ExceptionCaptureResult(
Metrics::CaptureResult::kSanitizationInitializationFailed);
return false;
}
if (!sanitized.Initialize(&process_snapshot,
sanitization_info.annotations_whitelist_address
? &whitelist
: nullptr,
sanitization_info.target_module_address,
sanitization_info.sanitize_stacks)) {
Metrics::ExceptionCaptureResult(
Metrics::CaptureResult::kSkippedDueToSanitization);
return true;
}
snapshot = &sanitized;
} else {
snapshot = &process_snapshot;
}
MinidumpFileWriter minidump; MinidumpFileWriter minidump;
minidump.InitializeFromSnapshot(&process_snapshot); minidump.InitializeFromSnapshot(snapshot);
AddUserExtensionStreams( AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump);
user_stream_data_sources_, &process_snapshot, &minidump);
if (!minidump.WriteEverything(new_report->Writer())) { if (!minidump.WriteEverything(new_report->Writer())) {
LOG(ERROR) << "WriteEverything failed"; LOG(ERROR) << "WriteEverything failed";

View File

@ -23,6 +23,7 @@
#include "handler/crash_report_upload_thread.h" #include "handler/crash_report_upload_thread.h"
#include "handler/linux/exception_handler_server.h" #include "handler/linux/exception_handler_server.h"
#include "handler/user_stream_data_source.h" #include "handler/user_stream_data_source.h"
#include "util/linux/exception_handler_protocol.h"
#include "util/linux/ptrace_connection.h" #include "util/linux/ptrace_connection.h"
#include "util/misc/address_types.h" #include "util/misc/address_types.h"
@ -63,15 +64,15 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate {
// ExceptionHandlerServer::Delegate: // ExceptionHandlerServer::Delegate:
bool HandleException(pid_t client_process_id, bool HandleException(pid_t client_process_id,
VMAddress exception_info_address) override; const ClientInformation& info) override;
bool HandleExceptionWithBroker(pid_t client_process_id, bool HandleExceptionWithBroker(pid_t client_process_id,
VMAddress exception_info_address, const ClientInformation& info,
int broker_sock) override; int broker_sock) override;
private: private:
bool HandleExceptionWithConnection(PtraceConnection* connection, bool HandleExceptionWithConnection(PtraceConnection* connection,
VMAddress exception_info_address); const ClientInformation& info);
CrashReportDatabase* database_; // weak CrashReportDatabase* database_; // weak
CrashReportUploadThread* upload_thread_; // weak CrashReportUploadThread* upload_thread_; // weak

View File

@ -446,15 +446,12 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest(
ServerToClientMessage::kTypeCrashDumpFailed); ServerToClientMessage::kTypeCrashDumpFailed);
case PtraceStrategyDecider::Strategy::kDirectPtrace: case PtraceStrategyDecider::Strategy::kDirectPtrace:
delegate_->HandleException(client_process_id, delegate_->HandleException(client_process_id, client_info);
client_info.exception_information_address);
break; break;
case PtraceStrategyDecider::Strategy::kUseBroker: case PtraceStrategyDecider::Strategy::kUseBroker:
delegate_->HandleExceptionWithBroker( delegate_->HandleExceptionWithBroker(
client_process_id, client_process_id, client_info, client_sock);
client_info.exception_information_address,
client_sock);
break; break;
} }

View File

@ -71,24 +71,21 @@ class ExceptionHandlerServer {
//! \brief Called on receipt of a crash dump request from a client. //! \brief Called on receipt of a crash dump request from a client.
//! //!
//! \param[in] client_process_id The process ID of the crashing client. //! \param[in] client_process_id The process ID of the crashing client.
//! \param[in] exception_information_address The address in the client's //! \param[in] info Information on the client.
//! address space of an ExceptionInformation struct.
//! \return `true` on success. `false` on failure with a message logged. //! \return `true` on success. `false` on failure with a message logged.
virtual bool HandleException(pid_t client_process_id, virtual bool HandleException(pid_t client_process_id,
VMAddress exception_information_address) = 0; const ClientInformation& info) = 0;
//! \brief Called on the receipt of a crash dump request from a client for a //! \brief Called on the receipt of a crash dump request from a client for a
//! crash that should be mediated by a PtraceBroker. //! crash that should be mediated by a PtraceBroker.
//! //!
//! \param[in] client_process_id The process ID of the crashing client. //! \param[in] client_process_id The process ID of the crashing client.
//! \param[in] exception_information_address The address in the client's //! \param[in] info Information on the client.
//! address space of an ExceptionInformation struct.
//! \param[in] broker_sock A socket connected to the PtraceBroker. //! \param[in] broker_sock A socket connected to the PtraceBroker.
//! \return `true` on success. `false` on failure with a message logged. //! \return `true` on success. `false` on failure with a message logged.
virtual bool HandleExceptionWithBroker( virtual bool HandleExceptionWithBroker(pid_t client_process_id,
pid_t client_process_id, const ClientInformation& info,
VMAddress exception_information_address, int broker_sock) = 0;
int broker_sock) = 0;
protected: protected:
~Delegate() {} ~Delegate() {}

View File

@ -101,25 +101,25 @@ class TestDelegate : public ExceptionHandlerServer::Delegate {
} }
bool HandleException(pid_t client_process_id, bool HandleException(pid_t client_process_id,
VMAddress exception_information_address) override { const ClientInformation& info) override {
DirectPtraceConnection connection; DirectPtraceConnection connection;
bool connected = connection.Initialize(client_process_id); bool connected = connection.Initialize(client_process_id);
EXPECT_TRUE(connected); EXPECT_TRUE(connected);
last_exception_address_ = exception_information_address; last_exception_address_ = info.exception_information_address;
last_client_ = client_process_id; last_client_ = client_process_id;
sem_.Signal(); sem_.Signal();
return connected; return connected;
} }
bool HandleExceptionWithBroker(pid_t client_process_id, bool HandleExceptionWithBroker(pid_t client_process_id,
VMAddress exception_information_address, const ClientInformation& info,
int broker_sock) override { int broker_sock) override {
PtraceClient client; PtraceClient client;
bool connected = client.Initialize(broker_sock, client_process_id); bool connected = client.Initialize(broker_sock, client_process_id);
EXPECT_TRUE(connected); EXPECT_TRUE(connected);
last_exception_address_ = exception_information_address, last_exception_address_ = info.exception_information_address,
last_client_ = client_process_id; last_client_ = client_process_id;
sem_.Signal(); sem_.Signal();
return connected; return connected;

View File

@ -128,6 +128,8 @@ static_library("snapshot") {
"sanitized/module_snapshot_sanitized.h", "sanitized/module_snapshot_sanitized.h",
"sanitized/process_snapshot_sanitized.cc", "sanitized/process_snapshot_sanitized.cc",
"sanitized/process_snapshot_sanitized.h", "sanitized/process_snapshot_sanitized.h",
"sanitized/sanitization_information.cc",
"sanitized/sanitization_information.h",
"sanitized/thread_snapshot_sanitized.cc", "sanitized/thread_snapshot_sanitized.cc",
"sanitized/thread_snapshot_sanitized.h", "sanitized/thread_snapshot_sanitized.h",
] ]
@ -338,6 +340,7 @@ source_set("snapshot_test") {
"linux/process_reader_linux_test.cc", "linux/process_reader_linux_test.cc",
"linux/system_snapshot_linux_test.cc", "linux/system_snapshot_linux_test.cc",
"sanitized/process_snapshot_sanitized_test.cc", "sanitized/process_snapshot_sanitized_test.cc",
"sanitized/sanitization_information_test.cc",
] ]
} else { } else {
sources += [ "crashpad_info_client_options_test.cc" ] sources += [ "crashpad_info_client_options_test.cc" ]

View File

@ -0,0 +1,61 @@
// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "snapshot/sanitized/sanitization_information.h"
#include "client/annotation.h"
namespace crashpad {
namespace {
template <typename Pointer>
bool ReadWhitelist(const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::string>* whitelist) {
if (!whitelist_address) {
return true;
}
std::vector<std::string> local_whitelist;
Pointer name_address;
while (memory.Read(whitelist_address, sizeof(name_address), &name_address)) {
if (!name_address) {
whitelist->swap(local_whitelist);
return true;
}
std::string name;
if (!memory.ReadCStringSizeLimited(
name_address, Annotation::kNameMaxLength, &name)) {
return false;
}
local_whitelist.push_back(name);
whitelist_address += sizeof(Pointer);
}
return false;
}
} // namespace
bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::string>* whitelist) {
return memory.Is64Bit()
? ReadWhitelist<uint64_t>(memory, whitelist_address, whitelist)
: ReadWhitelist<uint32_t>(memory, whitelist_address, whitelist);
}
} // namespace crashpad

View File

@ -0,0 +1,68 @@
// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_
#define CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "util/misc/address_types.h"
#include "util/process/process_memory_range.h"
namespace crashpad {
#pragma pack(push, 1)
//! \brief Struture containing information about how snapshots should be
//! sanitized.
//!
//! \see ProcessSnapshotSanitized
struct SanitizationInformation {
//! \brief The address in the client process' address space of a nullptr
//! terminated array of NUL-terminated strings. The string values are the
//! names of whitelisted annotations. This value is 0 if there is no
//! whitelist and all annotations are allowed.
VMAddress annotations_whitelist_address;
//! \brief An address in the client process' address space within a module to
//! target. When a target module is used, crash dumps are discarded unless
//! the crashing thread's program counter or pointer-aligned values on the
//! crashing thread's stack point into the target module. This value is 0
//! if there is no target module.
VMAddress target_module_address;
//! \brief Non-zero if stacks should be sanitized for possible PII.
uint8_t sanitize_stacks;
};
#pragma pack(pop)
//! \brief Reads an annotations whitelist from another process.
//!
//! \param[in] memory A memory reader for the target process.
//! \param[in] whitelist_address The address in the target process' address
//! space of a nullptr terminated array of NUL-terminated strings.
//! \param[out] whitelist The whitelist read, valid only if this function
//! returns `true`.
//! \return `true` on success, `false` on failure with a message logged.
bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::string>* whitelist);
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_

View File

@ -0,0 +1,70 @@
// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "snapshot/sanitized/sanitization_information.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "util/misc/from_pointer_cast.h"
#include "util/process/process_memory_linux.h"
namespace crashpad {
namespace test {
namespace {
class WhitelistTest : public testing::Test {
public:
void SetUp() override {
ASSERT_TRUE(memory_.Initialize(getpid()));
#if defined(ARCH_CPU_64_BITS)
ASSERT_TRUE(range_.Initialize(&memory_, true));
#else
ASSERT_TRUE(range_.Initialize(&memory_, false));
#endif
}
protected:
bool ReadWhitelist(const char* const* address) {
return ReadAnnotationsWhitelist(
range_, FromPointerCast<VMAddress>(address), &whitelist_);
}
ProcessMemoryLinux memory_;
ProcessMemoryRange range_;
std::vector<std::string> whitelist_;
};
const char* const kEmptyWhitelist[] = {nullptr};
TEST_F(WhitelistTest, EmptyWhitelist) {
ASSERT_TRUE(ReadWhitelist(kEmptyWhitelist));
EXPECT_EQ(whitelist_, std::vector<std::string>());
}
const char* const kNonEmptyWhitelist[] = {"string1",
"another_string",
"",
nullptr};
TEST_F(WhitelistTest, NonEmptyWhitelist) {
ASSERT_TRUE(ReadWhitelist(kNonEmptyWhitelist));
ASSERT_EQ(whitelist_.size(), arraysize(kNonEmptyWhitelist) - 1);
for (size_t index = 0; index < arraysize(kNonEmptyWhitelist) - 1; ++index) {
EXPECT_EQ(whitelist_[index], kNonEmptyWhitelist[index]);
}
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -129,6 +129,8 @@
'sanitized/module_snapshot_sanitized.h', 'sanitized/module_snapshot_sanitized.h',
'sanitized/process_snapshot_sanitized.cc', 'sanitized/process_snapshot_sanitized.cc',
'sanitized/process_snapshot_sanitized.h', 'sanitized/process_snapshot_sanitized.h',
'sanitized/sanitization_information.cc',
'sanitized/sanitization_information.h',
'sanitized/thread_snapshot_sanitized.cc', 'sanitized/thread_snapshot_sanitized.cc',
'sanitized/thread_snapshot_sanitized.h', 'sanitized/thread_snapshot_sanitized.h',
'snapshot_constants.h', 'snapshot_constants.h',

View File

@ -93,6 +93,7 @@
'minidump/process_snapshot_minidump_test.cc', 'minidump/process_snapshot_minidump_test.cc',
'posix/timezone_test.cc', 'posix/timezone_test.cc',
'sanitized/process_snapshot_sanitized_test.cc', 'sanitized/process_snapshot_sanitized_test.cc',
'sanitized/sanitization_information_test.cc',
'win/cpu_context_win_test.cc', 'win/cpu_context_win_test.cc',
'win/exception_snapshot_win_test.cc', 'win/exception_snapshot_win_test.cc',
'win/extra_memory_ranges_test.cc', 'win/extra_memory_ranges_test.cc',

View File

@ -281,6 +281,7 @@ static_library("util") {
"linux/direct_ptrace_connection.h", "linux/direct_ptrace_connection.h",
"linux/exception_handler_client.cc", "linux/exception_handler_client.cc",
"linux/exception_handler_client.h", "linux/exception_handler_client.h",
"linux/exception_handler_protocol.cc",
"linux/exception_handler_protocol.h", "linux/exception_handler_protocol.h",
"linux/exception_information.h", "linux/exception_information.h",
"linux/memory_map.cc", "linux/memory_map.cc",

View File

@ -0,0 +1,25 @@
// Copyright 2018 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/linux/exception_handler_protocol.h"
namespace crashpad {
ClientInformation::ClientInformation()
: exception_information_address(0), sanitization_information_address(0) {}
ClientToServerMessage::ClientToServerMessage()
: version(kVersion), type(kCrashDumpRequest), client_info() {}
} // namespace crashpad

View File

@ -35,17 +35,27 @@ enum Bool : char { kBoolFalse, kBoolTrue };
//! \brief Information about a client registered with an ExceptionHandlerServer. //! \brief Information about a client registered with an ExceptionHandlerServer.
struct ClientInformation { struct ClientInformation {
//! \brief Constructs this object.
ClientInformation();
//! \brief The address in the client's address space of an //! \brief The address in the client's address space of an
//! ExceptionInformation struct. //! ExceptionInformation struct.
VMAddress exception_information_address; VMAddress exception_information_address;
//! \brief The address in the client's address space of a
//! SanitizationInformation struct, or 0 if there is no such struct.
VMAddress sanitization_information_address;
}; };
//! \brief The message passed from client to server. //! \brief The message passed from client to server.
struct ClientToServerMessage { struct ClientToServerMessage {
static constexpr int32_t kVersion = 1; static constexpr int32_t kVersion = 1;
//! \brief Constructs this object.
ClientToServerMessage();
//! \brief Indicates what message version is being used. //! \brief Indicates what message version is being used.
int32_t version = kVersion; int32_t version;
enum Type : uint32_t { enum Type : uint32_t {
//! \brief Used to request a crash dump for the sending client. //! \brief Used to request a crash dump for the sending client.

View File

@ -129,6 +129,12 @@ class Metrics {
//! This value is only used on Linux/Android. //! This value is only used on Linux/Android.
kBrokeredPtraceFailed = 9, kBrokeredPtraceFailed = 9,
//! \brief Sanitization was requested but could not be initialized.
kSanitizationInitializationFailed = 10,
//! \brief Sanitization caused this crash dump to be skipped.
kSkippedDueToSanitization = 11,
//! \brief The number of values in this enumeration; not a valid value. //! \brief The number of values in this enumeration; not a valid value.
kMaxValue kMaxValue
}; };

View File

@ -60,6 +60,7 @@
'linux/direct_ptrace_connection.h', 'linux/direct_ptrace_connection.h',
'linux/exception_handler_client.cc', 'linux/exception_handler_client.cc',
'linux/exception_handler_client.h', 'linux/exception_handler_client.h',
'linux/exception_handler_protocol.cc',
'linux/exception_handler_protocol.h', 'linux/exception_handler_protocol.h',
'linux/exception_information.h', 'linux/exception_information.h',
'linux/memory_map.cc', 'linux/memory_map.cc',