From d1e6a2130da4a6f4005a7729ad12420ce6c9a486 Mon Sep 17 00:00:00 2001 From: Joshua Peraza Date: Tue, 12 Jun 2018 08:30:36 -0700 Subject: [PATCH] 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 Reviewed-by: Scott Graham --- client/crashpad_client_linux_test.cc | 49 +++++++++---- handler/handler_main.cc | 35 ++++++++-- .../linux/crash_report_exception_handler.cc | 61 +++++++++++++--- .../linux/crash_report_exception_handler.h | 7 +- handler/linux/exception_handler_server.cc | 7 +- handler/linux/exception_handler_server.h | 15 ++-- .../linux/exception_handler_server_test.cc | 8 +-- snapshot/BUILD.gn | 3 + .../sanitized/sanitization_information.cc | 61 ++++++++++++++++ snapshot/sanitized/sanitization_information.h | 68 ++++++++++++++++++ .../sanitization_information_test.cc | 70 +++++++++++++++++++ snapshot/snapshot.gyp | 2 + snapshot/snapshot_test.gyp | 1 + util/BUILD.gn | 1 + util/linux/exception_handler_protocol.cc | 25 +++++++ util/linux/exception_handler_protocol.h | 12 +++- util/misc/metrics.h | 6 ++ util/util.gyp | 1 + 18 files changed, 385 insertions(+), 47 deletions(-) create mode 100644 snapshot/sanitized/sanitization_information.cc create mode 100644 snapshot/sanitized/sanitization_information.h create mode 100644 snapshot/sanitized/sanitization_information_test.cc create mode 100644 util/linux/exception_handler_protocol.cc diff --git a/client/crashpad_client_linux_test.cc b/client/crashpad_client_linux_test.cc index bacfcae3..4c5bf4de 100644 --- a/client/crashpad_client_linux_test.cc +++ b/client/crashpad_client_linux_test.cc @@ -28,6 +28,7 @@ #include "gtest/gtest.h" #include "snapshot/annotation_snapshot.h" #include "snapshot/minidump/process_snapshot_minidump.h" +#include "snapshot/sanitized/sanitization_information.h" #include "test/multiprocess.h" #include "test/multiprocess_exec.h" #include "test/scoped_temp_dir.h" @@ -210,7 +211,9 @@ class StartHandlerForClientTest { StartHandlerForClientTest() = default; ~StartHandlerForClientTest() = default; - bool Initialize() { + bool Initialize(bool sanitize) { + sanitize_ = sanitize; + int socks[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) { PLOG(ERROR) << "socketpair"; @@ -253,19 +256,23 @@ class StartHandlerForClientTest { ASSERT_TRUE(database); std::vector reports; - ASSERT_EQ(database->GetPendingReports(&reports), - CrashReportDatabase::kNoError); - EXPECT_EQ(reports.size(), 1u); - - reports.clear(); ASSERT_EQ(database->GetCompletedReports(&reports), CrashReportDatabase::kNoError); 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() { auto signal_handler = SandboxedHandler::Get(); - return signal_handler->Initialize(client_sock_.get()); + return signal_handler->Initialize(client_sock_.get(), sanitize_); } private: @@ -278,8 +285,9 @@ class StartHandlerForClientTest { return instance; } - bool Initialize(FileHandle client_sock) { + bool Initialize(FileHandle client_sock, bool sanitize) { client_sock_ = client_sock; + sanitize_ = sanitize; return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr); } @@ -302,11 +310,20 @@ class StartHandlerForClientTest { context); exception_information.thread_id = syscall(SYS_gettid); - ClientInformation info = {}; + ClientInformation info; info.exception_information_address = FromPointerCast( &exception_information); + SanitizationInformation sanitization_info = {}; + if (state->sanitize_) { + info.sanitization_information_address = + FromPointerCast(&sanitization_info); + // Target a non-module address to prevent a crash dump. + sanitization_info.target_module_address = + FromPointerCast(&sanitization_info); + } + ExceptionHandlerClient handler_client(state->client_sock_); CHECK_EQ(handler_client.RequestCrashDump(info), 0); @@ -314,6 +331,7 @@ class StartHandlerForClientTest { } FileHandle client_sock_; + bool sanitize_; DISALLOW_COPY_AND_ASSIGN(SandboxedHandler); }; @@ -321,6 +339,7 @@ class StartHandlerForClientTest { ScopedTempDir temp_dir_; ScopedFileHandle client_sock_; ScopedFileHandle server_sock_; + bool sanitize_; DISALLOW_COPY_AND_ASSIGN(StartHandlerForClientTest); }; @@ -331,9 +350,9 @@ class StartHandlerForChildTest : public Multiprocess { StartHandlerForChildTest() = default; ~StartHandlerForChildTest() = default; - bool Initialize() { + bool Initialize(bool sanitize) { SetExpectedChildTerminationBuiltinTrap(); - return test_state_.Initialize(); + return test_state_.Initialize(sanitize); } private: @@ -361,7 +380,13 @@ class StartHandlerForChildTest : public Multiprocess { TEST(CrashpadClient, StartHandlerForChild) { 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(); } diff --git a/handler/handler_main.cc b/handler/handler_main.cc index 901ee221..230feb41 100644 --- a/handler/handler_main.cc +++ b/handler/handler_main.cc @@ -144,6 +144,8 @@ void Usage(const base::FilePath& me) { " --trace-parent-with-exception=EXCEPTION_INFORMATION_ADDRESS\n" " request a dump for the handler's parent process\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 " --url=URL send crash reports to this Breakpad server URL,\n" " only if uploads are enabled for the database\n" @@ -167,6 +169,7 @@ struct Options { #elif defined(OS_LINUX) || defined(OS_ANDROID) VMAddress exception_information_address; int initial_client_fd; + VMAddress sanitization_information_address; #elif defined(OS_WIN) std::string pipe_name; InitialClientData initial_client_data; @@ -535,6 +538,7 @@ int HandlerMain(int argc, #if defined(OS_LINUX) || defined(OS_ANDROID) kOptionTraceParentWithException, kOptionInitialClientFD, + kOptionSanitizationInformation, #endif kOptionURL, @@ -590,6 +594,10 @@ int HandlerMain(int argc, nullptr, kOptionTraceParentWithException}, {"initial-client-fd", required_argument, nullptr, kOptionInitialClientFD}, + {"sanitization-information", + required_argument, + nullptr, + kOptionSanitizationInformation}, #endif // OS_LINUX || OS_ANDROID {"url", required_argument, nullptr, kOptionURL}, {"help", no_argument, nullptr, kOptionHelp}, @@ -608,6 +616,7 @@ int HandlerMain(int argc, #if defined(OS_LINUX) || defined(OS_ANDROID) options.exception_information_address = 0; options.initial_client_fd = kInvalidFileHandle; + options.sanitization_information_address = 0; #endif int opt; @@ -714,6 +723,15 @@ int HandlerMain(int argc, } 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 case kOptionURL: { options.url = optarg; @@ -762,9 +780,15 @@ int HandlerMain(int argc, #elif defined(OS_LINUX) || defined(OS_ANDROID) if (!options.exception_information_address && 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( me, - "--exception_information_address or --initial_client_fd is required"); + "--sanitization_information requires --trace-parent-with-exception"); return ExitFailure(); } #endif // OS_MACOSX @@ -844,9 +868,12 @@ int HandlerMain(int argc, #if defined(OS_LINUX) || defined(OS_ANDROID) if (options.exception_information_address) { - return exception_handler.HandleException(getppid(), - options.exception_information_address) ? - EXIT_SUCCESS : ExitFailure(); + ClientInformation info; + info.exception_information_address = options.exception_information_address; + info.sanitization_information_address = + options.sanitization_information_address; + return exception_handler.HandleException(getppid(), info) ? EXIT_SUCCESS + : ExitFailure(); } #endif // OS_LINUX || OS_ANDROID diff --git a/handler/linux/crash_report_exception_handler.cc b/handler/linux/crash_report_exception_handler.cc index 2f38f2c0..101c49f5 100644 --- a/handler/linux/crash_report_exception_handler.cc +++ b/handler/linux/crash_report_exception_handler.cc @@ -21,6 +21,8 @@ #include "minidump/minidump_file_writer.h" #include "snapshot/crashpad_info_client_options.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/ptrace_client.h" #include "util/misc/metrics.h" @@ -43,7 +45,7 @@ CrashReportExceptionHandler::~CrashReportExceptionHandler() = default; bool CrashReportExceptionHandler::HandleException( pid_t client_process_id, - VMAddress exception_info_address) { + const ClientInformation& info) { Metrics::ExceptionEncountered(); DirectPtraceConnection connection; @@ -53,12 +55,12 @@ bool CrashReportExceptionHandler::HandleException( return false; } - return HandleExceptionWithConnection(&connection, exception_info_address); + return HandleExceptionWithConnection(&connection, info); } bool CrashReportExceptionHandler::HandleExceptionWithBroker( pid_t client_process_id, - VMAddress exception_info_address, + const ClientInformation& info, int broker_sock) { Metrics::ExceptionEncountered(); @@ -69,19 +71,20 @@ bool CrashReportExceptionHandler::HandleExceptionWithBroker( return false; } - return HandleExceptionWithConnection(&client, exception_info_address); + return HandleExceptionWithConnection(&client, info); } bool CrashReportExceptionHandler::HandleExceptionWithConnection( PtraceConnection* connection, - VMAddress exception_info_address) { + const ClientInformation& info) { ProcessSnapshotLinux process_snapshot; if (!process_snapshot.Initialize(connection)) { Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kSnapshotFailed); return false; } - if (!process_snapshot.InitializeException(exception_info_address)) { + if (!process_snapshot.InitializeException( + info.exception_information_address)) { Metrics::ExceptionCaptureResult( Metrics::CaptureResult::kExceptionInitializationFailed); return false; @@ -116,10 +119,50 @@ bool CrashReportExceptionHandler::HandleExceptionWithConnection( process_snapshot.SetReportID(new_report->ReportID()); + ProcessSnapshot* snapshot = nullptr; + ProcessSnapshotSanitized sanitized; + std::vector 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; - minidump.InitializeFromSnapshot(&process_snapshot); - AddUserExtensionStreams( - user_stream_data_sources_, &process_snapshot, &minidump); + minidump.InitializeFromSnapshot(snapshot); + AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump); if (!minidump.WriteEverything(new_report->Writer())) { LOG(ERROR) << "WriteEverything failed"; diff --git a/handler/linux/crash_report_exception_handler.h b/handler/linux/crash_report_exception_handler.h index ca14f81a..24d5995a 100644 --- a/handler/linux/crash_report_exception_handler.h +++ b/handler/linux/crash_report_exception_handler.h @@ -23,6 +23,7 @@ #include "handler/crash_report_upload_thread.h" #include "handler/linux/exception_handler_server.h" #include "handler/user_stream_data_source.h" +#include "util/linux/exception_handler_protocol.h" #include "util/linux/ptrace_connection.h" #include "util/misc/address_types.h" @@ -63,15 +64,15 @@ class CrashReportExceptionHandler : public ExceptionHandlerServer::Delegate { // ExceptionHandlerServer::Delegate: bool HandleException(pid_t client_process_id, - VMAddress exception_info_address) override; + const ClientInformation& info) override; bool HandleExceptionWithBroker(pid_t client_process_id, - VMAddress exception_info_address, + const ClientInformation& info, int broker_sock) override; private: bool HandleExceptionWithConnection(PtraceConnection* connection, - VMAddress exception_info_address); + const ClientInformation& info); CrashReportDatabase* database_; // weak CrashReportUploadThread* upload_thread_; // weak diff --git a/handler/linux/exception_handler_server.cc b/handler/linux/exception_handler_server.cc index 447093dc..748bf6e9 100644 --- a/handler/linux/exception_handler_server.cc +++ b/handler/linux/exception_handler_server.cc @@ -446,15 +446,12 @@ bool ExceptionHandlerServer::HandleCrashDumpRequest( ServerToClientMessage::kTypeCrashDumpFailed); case PtraceStrategyDecider::Strategy::kDirectPtrace: - delegate_->HandleException(client_process_id, - client_info.exception_information_address); + delegate_->HandleException(client_process_id, client_info); break; case PtraceStrategyDecider::Strategy::kUseBroker: delegate_->HandleExceptionWithBroker( - client_process_id, - client_info.exception_information_address, - client_sock); + client_process_id, client_info, client_sock); break; } diff --git a/handler/linux/exception_handler_server.h b/handler/linux/exception_handler_server.h index 1c02a441..5f491826 100644 --- a/handler/linux/exception_handler_server.h +++ b/handler/linux/exception_handler_server.h @@ -71,24 +71,21 @@ class ExceptionHandlerServer { //! \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] exception_information_address The address in the client's - //! address space of an ExceptionInformation struct. + //! \param[in] info Information on the client. //! \return `true` on success. `false` on failure with a message logged. 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 //! crash that should be mediated by a PtraceBroker. //! //! \param[in] client_process_id The process ID of the crashing client. - //! \param[in] exception_information_address The address in the client's - //! address space of an ExceptionInformation struct. + //! \param[in] info Information on the client. //! \param[in] broker_sock A socket connected to the PtraceBroker. //! \return `true` on success. `false` on failure with a message logged. - virtual bool HandleExceptionWithBroker( - pid_t client_process_id, - VMAddress exception_information_address, - int broker_sock) = 0; + virtual bool HandleExceptionWithBroker(pid_t client_process_id, + const ClientInformation& info, + int broker_sock) = 0; protected: ~Delegate() {} diff --git a/handler/linux/exception_handler_server_test.cc b/handler/linux/exception_handler_server_test.cc index 247ac8c6..eda14d31 100644 --- a/handler/linux/exception_handler_server_test.cc +++ b/handler/linux/exception_handler_server_test.cc @@ -101,25 +101,25 @@ class TestDelegate : public ExceptionHandlerServer::Delegate { } bool HandleException(pid_t client_process_id, - VMAddress exception_information_address) override { + const ClientInformation& info) override { DirectPtraceConnection connection; bool connected = connection.Initialize(client_process_id); EXPECT_TRUE(connected); - last_exception_address_ = exception_information_address; + last_exception_address_ = info.exception_information_address; last_client_ = client_process_id; sem_.Signal(); return connected; } bool HandleExceptionWithBroker(pid_t client_process_id, - VMAddress exception_information_address, + const ClientInformation& info, int broker_sock) override { PtraceClient client; bool connected = client.Initialize(broker_sock, client_process_id); EXPECT_TRUE(connected); - last_exception_address_ = exception_information_address, + last_exception_address_ = info.exception_information_address, last_client_ = client_process_id; sem_.Signal(); return connected; diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn index f8a055bd..6bafabb3 100644 --- a/snapshot/BUILD.gn +++ b/snapshot/BUILD.gn @@ -128,6 +128,8 @@ static_library("snapshot") { "sanitized/module_snapshot_sanitized.h", "sanitized/process_snapshot_sanitized.cc", "sanitized/process_snapshot_sanitized.h", + "sanitized/sanitization_information.cc", + "sanitized/sanitization_information.h", "sanitized/thread_snapshot_sanitized.cc", "sanitized/thread_snapshot_sanitized.h", ] @@ -338,6 +340,7 @@ source_set("snapshot_test") { "linux/process_reader_linux_test.cc", "linux/system_snapshot_linux_test.cc", "sanitized/process_snapshot_sanitized_test.cc", + "sanitized/sanitization_information_test.cc", ] } else { sources += [ "crashpad_info_client_options_test.cc" ] diff --git a/snapshot/sanitized/sanitization_information.cc b/snapshot/sanitized/sanitization_information.cc new file mode 100644 index 00000000..f7be9b08 --- /dev/null +++ b/snapshot/sanitized/sanitization_information.cc @@ -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 +bool ReadWhitelist(const ProcessMemoryRange& memory, + VMAddress whitelist_address, + std::vector* whitelist) { + if (!whitelist_address) { + return true; + } + + std::vector 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* whitelist) { + return memory.Is64Bit() + ? ReadWhitelist(memory, whitelist_address, whitelist) + : ReadWhitelist(memory, whitelist_address, whitelist); +} + +} // namespace crashpad diff --git a/snapshot/sanitized/sanitization_information.h b/snapshot/sanitized/sanitization_information.h new file mode 100644 index 00000000..6a6d9089 --- /dev/null +++ b/snapshot/sanitized/sanitization_information.h @@ -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 + +#include +#include + +#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* whitelist); + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_SANITIZED_SANITIZATION_INFORMATION_H_ diff --git a/snapshot/sanitized/sanitization_information_test.cc b/snapshot/sanitized/sanitization_information_test.cc new file mode 100644 index 00000000..a7bf8265 --- /dev/null +++ b/snapshot/sanitized/sanitization_information_test.cc @@ -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(address), &whitelist_); + } + + ProcessMemoryLinux memory_; + ProcessMemoryRange range_; + std::vector whitelist_; +}; + +const char* const kEmptyWhitelist[] = {nullptr}; + +TEST_F(WhitelistTest, EmptyWhitelist) { + ASSERT_TRUE(ReadWhitelist(kEmptyWhitelist)); + EXPECT_EQ(whitelist_, std::vector()); +} + +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 diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 3aad7bae..a78d21f9 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -129,6 +129,8 @@ 'sanitized/module_snapshot_sanitized.h', 'sanitized/process_snapshot_sanitized.cc', 'sanitized/process_snapshot_sanitized.h', + 'sanitized/sanitization_information.cc', + 'sanitized/sanitization_information.h', 'sanitized/thread_snapshot_sanitized.cc', 'sanitized/thread_snapshot_sanitized.h', 'snapshot_constants.h', diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index c2ec97d3..fc746f2c 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -93,6 +93,7 @@ 'minidump/process_snapshot_minidump_test.cc', 'posix/timezone_test.cc', 'sanitized/process_snapshot_sanitized_test.cc', + 'sanitized/sanitization_information_test.cc', 'win/cpu_context_win_test.cc', 'win/exception_snapshot_win_test.cc', 'win/extra_memory_ranges_test.cc', diff --git a/util/BUILD.gn b/util/BUILD.gn index abb55d5f..03220c9e 100644 --- a/util/BUILD.gn +++ b/util/BUILD.gn @@ -281,6 +281,7 @@ static_library("util") { "linux/direct_ptrace_connection.h", "linux/exception_handler_client.cc", "linux/exception_handler_client.h", + "linux/exception_handler_protocol.cc", "linux/exception_handler_protocol.h", "linux/exception_information.h", "linux/memory_map.cc", diff --git a/util/linux/exception_handler_protocol.cc b/util/linux/exception_handler_protocol.cc new file mode 100644 index 00000000..3feca698 --- /dev/null +++ b/util/linux/exception_handler_protocol.cc @@ -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 diff --git a/util/linux/exception_handler_protocol.h b/util/linux/exception_handler_protocol.h index 3f71abf7..4ba1b5d0 100644 --- a/util/linux/exception_handler_protocol.h +++ b/util/linux/exception_handler_protocol.h @@ -35,17 +35,27 @@ enum Bool : char { kBoolFalse, kBoolTrue }; //! \brief Information about a client registered with an ExceptionHandlerServer. struct ClientInformation { + //! \brief Constructs this object. + ClientInformation(); + //! \brief The address in the client's address space of an //! ExceptionInformation struct. 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. struct ClientToServerMessage { static constexpr int32_t kVersion = 1; + //! \brief Constructs this object. + ClientToServerMessage(); + //! \brief Indicates what message version is being used. - int32_t version = kVersion; + int32_t version; enum Type : uint32_t { //! \brief Used to request a crash dump for the sending client. diff --git a/util/misc/metrics.h b/util/misc/metrics.h index 54ccb843..3e9337a9 100644 --- a/util/misc/metrics.h +++ b/util/misc/metrics.h @@ -129,6 +129,12 @@ class Metrics { //! This value is only used on Linux/Android. 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. kMaxValue }; diff --git a/util/util.gyp b/util/util.gyp index 4cbc13e1..1ffb752c 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -60,6 +60,7 @@ 'linux/direct_ptrace_connection.h', 'linux/exception_handler_client.cc', 'linux/exception_handler_client.h', + 'linux/exception_handler_protocol.cc', 'linux/exception_handler_protocol.h', 'linux/exception_information.h', 'linux/memory_map.cc',