Commit b8488871 authored by Joshua Peraza's avatar Joshua Peraza Committed by Commit Bot

Update Crashpad to 0cccdc0b7ec32bd31e789b3945a08c04ef775834

9cd1a4dadb51 doc: Upgrade the crashpad-home App Engine app to the Go
             1.11 runtime
94b7e45210a7 fix OS guards for attachments
2f66eefb7921 Update language to eliminate 'whitelist'
0cccdc0b7ec3 Replace is_linux with is_linux || is_chromeos

Change-Id: Ia91ba57d7051b49d398f3cfa18c335cf6303e993
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2341940
Commit-Queue: Matthew Denton <mpdenton@chromium.org>
Auto-Submit: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Reviewed-by: default avatarMatthew Denton <mpdenton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795766}
parent 00719dda
......@@ -187,10 +187,10 @@ bool CrashReporterClient::ShouldWriteMinidumpToLog() {
#if defined(OS_ANDROID) || defined(OS_LINUX)
void CrashReporterClient::GetSanitizationInformation(
const char* const** annotations_whitelist,
const char* const** allowed_annotations,
void** target_module,
bool* sanitize_stacks) {
*annotations_whitelist = nullptr;
*allowed_annotations = nullptr;
*target_module = nullptr;
*sanitize_stacks = false;
}
......
......@@ -188,9 +188,9 @@ void DumpProcessWithoutCrashing(task_t task_port);
class CrashReporterClient;
bool DumpWithoutCrashingForClient(CrashReporterClient* client);
// Used under WebView to whitelist a memory range so it's accessible using
// crashpad's ProcessMemory interface.
void WhitelistMemoryRange(void* begin, size_t size);
// If a CrashReporterClient has enabled sanitization, this function specifies
// regions of memory which are allowed to be collected by Crashpad.
void AllowMemoryRange(void* begin, size_t size);
#endif // OS_ANDROID
#if defined(OS_LINUX)
......
......@@ -52,56 +52,59 @@
namespace crashpad {
namespace {
class MemoryRangeWhitelist {
class AllowedMemoryRanges {
public:
MemoryRangeWhitelist() {
whitelist_.entries = 0;
whitelist_.size = 0;
AllowedMemoryRanges() {
allowed_memory_ranges_.entries = 0;
allowed_memory_ranges_.size = 0;
}
void AddEntry(VMAddress base, VMSize length) {
SanitizationMemoryRangeWhitelist::Range new_entry;
SanitizationAllowedMemoryRanges::Range new_entry;
new_entry.base = base;
new_entry.length = length;
base::AutoLock lock(lock_);
std::vector<SanitizationMemoryRangeWhitelist::Range> new_array(array_);
std::vector<SanitizationAllowedMemoryRanges::Range> new_array(array_);
new_array.push_back(new_entry);
whitelist_.entries = FromPointerCast<VMAddress>(new_array.data());
whitelist_.size += 1;
allowed_memory_ranges_.entries =
FromPointerCast<VMAddress>(new_array.data());
allowed_memory_ranges_.size += 1;
array_ = std::move(new_array);
}
SanitizationMemoryRangeWhitelist* GetSanitizationAddress() {
return &whitelist_;
SanitizationAllowedMemoryRanges* GetSanitizationAddress() {
return &allowed_memory_ranges_;
}
static MemoryRangeWhitelist* Singleton() {
static base::NoDestructor<MemoryRangeWhitelist> singleton;
static AllowedMemoryRanges* Singleton() {
static base::NoDestructor<AllowedMemoryRanges> singleton;
return singleton.get();
}
private:
base::Lock lock_;
SanitizationMemoryRangeWhitelist whitelist_;
std::vector<SanitizationMemoryRangeWhitelist::Range> array_;
SanitizationAllowedMemoryRanges allowed_memory_ranges_;
std::vector<SanitizationAllowedMemoryRanges::Range> array_;
DISALLOW_COPY_AND_ASSIGN(MemoryRangeWhitelist);
DISALLOW_COPY_AND_ASSIGN(AllowedMemoryRanges);
};
bool SetSanitizationInfo(crash_reporter::CrashReporterClient* client,
SanitizationInformation* info) {
const char* const* whitelist = nullptr;
const char* const* allowed_annotations = nullptr;
void* target_module = nullptr;
bool sanitize_stacks = false;
client->GetSanitizationInformation(&whitelist, &target_module,
client->GetSanitizationInformation(&allowed_annotations, &target_module,
&sanitize_stacks);
info->annotations_whitelist_address = FromPointerCast<VMAddress>(whitelist);
info->allowed_annotations_address =
FromPointerCast<VMAddress>(allowed_annotations);
info->target_module_address = FromPointerCast<VMAddress>(target_module);
info->memory_range_whitelist_address = FromPointerCast<VMAddress>(
MemoryRangeWhitelist::Singleton()->GetSanitizationAddress());
info->allowed_memory_ranges_address = FromPointerCast<VMAddress>(
AllowedMemoryRanges::Singleton()->GetSanitizationAddress());
info->sanitize_stacks = sanitize_stacks;
return whitelist != nullptr || target_module != nullptr || sanitize_stacks;
return allowed_annotations != nullptr || target_module != nullptr ||
sanitize_stacks;
}
void SetExceptionInformation(siginfo_t* siginfo,
......@@ -689,8 +692,8 @@ bool DumpWithoutCrashingForClient(CrashReporterClient* client) {
return handler_client.RequestCrashDump(info) == 0;
}
void WhitelistMemoryRange(void* begin, size_t length) {
crashpad::MemoryRangeWhitelist::Singleton()->AddEntry(
void AllowMemoryRange(void* begin, size_t length) {
crashpad::AllowedMemoryRanges::Singleton()->AddEntry(
crashpad::FromPointerCast<crashpad::VMAddress>(begin),
static_cast<crashpad::VMSize>(length));
}
......
......@@ -189,11 +189,11 @@ void GuardedPageAllocator::Init(size_t max_alloced_pages,
state_.metadata_addr = reinterpret_cast<uintptr_t>(metadata_.get());
#if defined(OS_ANDROID)
// Explicitly whitelist memory ranges the crash_handler needs to reads. This
// is required for WebView because it has a stricter set of privacy
// constraints on what it reads from the crashing process.
// Explicitly allow memory ranges the crash_handler needs to read. This is
// required for WebView because it has a stricter set of privacy constraints
// on what it reads from the crashing process.
for (auto& region : GetInternalMemoryRegions())
crash_reporter::WhitelistMemoryRange(region.first, region.second);
crash_reporter::AllowMemoryRange(region.first, region.second);
#endif
}
......
......@@ -124,22 +124,22 @@ MULTIPROCESS_TEST_MAIN(CrashingProcess) {
#if defined(OS_LINUX) || defined(OS_ANDROID)
static crashpad::SanitizationInformation sanitization_info = {};
static crashpad::SanitizationMemoryRangeWhitelist memory_whitelist;
static crashpad::SanitizationAllowedMemoryRanges allowed_memory_ranges;
if (cmd_line->HasSwitch("sanitize")) {
auto memory_ranges = gpa->GetInternalMemoryRegions();
auto* range_array =
new crashpad::SanitizationMemoryRangeWhitelist::Range[memory_ranges
.size()];
new crashpad::SanitizationAllowedMemoryRanges::Range[memory_ranges
.size()];
for (size_t i = 0; i < memory_ranges.size(); i++) {
range_array[i].base =
reinterpret_cast<crashpad::VMAddress>(memory_ranges[i].first);
range_array[i].length = memory_ranges[i].second;
}
memory_whitelist.size = memory_ranges.size();
memory_whitelist.entries =
allowed_memory_ranges.size = memory_ranges.size();
allowed_memory_ranges.entries =
reinterpret_cast<crashpad::VMAddress>(range_array);
sanitization_info.memory_range_whitelist_address =
reinterpret_cast<crashpad::VMAddress>(&memory_whitelist);
sanitization_info.allowed_memory_ranges_address =
reinterpret_cast<crashpad::VMAddress>(&allowed_memory_ranges);
arguments.push_back(base::StringPrintf("--sanitization-information=%p",
&sanitization_info));
}
......
......@@ -2,7 +2,7 @@ Name: Crashpad
Short Name: crashpad
URL: https://crashpad.chromium.org/
Version: unknown
Revision: 4ae896bad0af491e183269f5783c2c90a87ba9c9
Revision: 0cccdc0b7ec32bd31e789b3945a08c04ef775834
License: Apache 2.0
License File: crashpad/LICENSE
Security Critical: yes
......
......@@ -292,7 +292,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line):
# pseudo-terminal device, Google Test will not normally enable colored
# output, so mimic Google Test’s own logic for deciding whether to
# enable color by checking this script’s own standard output connection.
# The whitelist of TERM values comes from Google Test’s
# The list of TERM values comes from Google Test’s
# googletest/src/gtest.cc testing::internal::ShouldUseColor().
env = {'CRASHPAD_TEST_DATA_ROOT': device_temp_dir}
gtest_color = os.environ.get('GTEST_COLOR')
......
This is the App Engine app that serves https://crashpad.chromium.org/.
To work on this app, obtain the App Engine SDK for Go from
https://cloud.google.com/appengine/docs/go/download. Unpacking it produces a
go_appengine directory. This may be added to your $PATH for convenience,
although it is not necessary.
To work on this app, obtain the following packages:
- Go, from https://golang.org/dl/. This is only necessary for local development
and testing. The directory containing the “go” executable, such as
/usr/local/go/bin, must appear in $PATH. It does not appear critical for the
Go version used to match the Go runtime version used (for example, these
instructions were tested with Go 1.14 locally but a Go 1.11 runtime when
deployed), but if problems are encountered, it would be wise to use the same
version for both local development and AppEngine deployment.
- The Google Cloud SDK from, https://cloud.google.com/sdk/docs. This is
necessary for both local development and for AppEngine deployment. Unpacking
this package produces a google-cloud-sdk directory, whose bin child directory
may be added to $PATH for convenience, although this is not strictly
necessary.
The commands in this README are expected to be run from the directory containing
app.yaml.
it. $GOPATH must also be set to include this directory:
The App Engine SDK for Go provides App Engine packages at the “appengine” import
path, but not the newer “google.golang.org/appengine” path. The Crashpad app
uses the newer paths. See
https://github.com/golang/appengine#2-update-import-paths and
https://code.google.com/p/googleappengine/issues/detail?id=11670. To make these
available, obtain a Go release from https://golang.org/dl/, and run:
$ GOROOT=…/go_appengine/goroot GOPATH=…/go_appengine/gopath go get -d
% export GOPATH="$(go env GOPATH):$(pwd)"
To test locally:
$ …/go_appengine/goapp serve
% go get -d crashpad-home
% …/google-cloud-sdk/bin/dev_appserver.py src/crashpad-home
Look for the “Starting module "default" running at: http://localhost:8080” line,
which tells you the URL of the local running instance of the app.
which tells you the URL of the local running instance of the app. Test
http://localhost:8080/ and http://localhost:8080/doxygen to ensure that they
work.
To deploy:
$ version=$(git rev-parse --short=12 HEAD)
$ [[ -n "$(git status --porcelain)" ]] && version+=-dirty
$ …/go_appengine/goapp deploy -version "${version}"
% version=$(git rev-parse --short=12 HEAD)
% [[ -n "$(git status --porcelain)" ]] && version+=-dirty
% …/google-cloud-sdk/bin/gcloud app deploy \
--project=crashpad-home --version="${version}" --no-promote \
"$(pwd)/src/crashpad-home"
Note that app.yaml does not name a “version” to encourage you to use a git hash
as the version, as above.
(Note: the $(pwd) is necessary for “gcloud app deploy” to recognize that the
application is in GOPATH, putting it into “GOPATH mode”. This normally happens
correctly on its own even with a relative path, but will fail for relative
paths when $(pwd) is a symbolic link. Using an absolute path here will save you
from this frustration, freeing you up to undoubtedly experience other
frustrations.)
Activate a newly-deployed version by visiting the App Engine console at
https://appengine.google.com/deployment?&app_id=s~crashpad-home, selecting it,
and choosing “Make Default”. It is also possible to delete old versions from
this page when they are no longer needed.
https://console.cloud.google.com/appengine/versions?project=crashpad-home,
selecting it, and choosing “Migrate Traffic”. It is also possible to delete old
versions from this page when they are no longer needed.
application: crashpad-home
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
secure: always
# Copyright 2015 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.
runtime: go111
handlers:
- url: /.*
script: auto
secure: always
......@@ -12,8 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package crashpad mirrors crashpad documentation from Chromium’s git repo.
package crashpad
package main
import (
"encoding/base64"
......@@ -31,6 +30,10 @@ import (
"google.golang.org/appengine/urlfetch"
)
func main() {
appengine.Main()
}
func init() {
http.HandleFunc("/", handler)
}
......
......@@ -95,16 +95,21 @@ namespace crashpad {
namespace {
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_ANDROID)
#define ATTACHMENTS_SUPPORTED 1
#endif // OS_WIN || OS_LINUX || OS_CHROMEOS || OS_ANDROID
void Usage(const base::FilePath& me) {
fprintf(stderr,
"Usage: %" PRFilePath " [OPTION]...\n"
"Crashpad's exception handler server.\n"
"\n"
" --annotation=KEY=VALUE set a process annotation in each crash report\n"
#if defined(OS_WIN) || defined(OS_LINUX)
#if defined(ATTACHMENTS_SUPPORTED)
" --attachment=FILE_PATH attach specified file to each crash report\n"
" at the time of the crash\n"
#endif // OS_WIN || OS_LINUX
#endif // ATTACHMENTS_SUPPORTED
" --database=PATH store the crash report database at PATH\n"
#if defined(OS_APPLE)
" --handshake-fd=FD establish communication with the client over FD\n"
......@@ -215,10 +220,9 @@ struct Options {
base::FilePath minidump_dir_for_tests;
bool always_allow_feedback = false;
#endif // OS_CHROMEOS
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_ANDROID)
#if defined(ATTACHMENTS_SUPPORTED)
std::vector<base::FilePath> attachments;
#endif // OS_WIN || OS_LINUX
#endif // ATTACHMENTS_SUPPORTED
};
// Splits |key_value| on '=' and inserts the resulting key and value into |map|.
......@@ -580,9 +584,9 @@ int HandlerMain(int argc,
static constexpr option long_options[] = {
{"annotation", required_argument, nullptr, kOptionAnnotation},
#if defined(OS_WIN) || defined(OS_LINUX)
#if defined(ATTACHMENTS_SUPPORTED)
{"attachment", required_argument, nullptr, kOptionAttachment},
#endif // OS_WIN || OS_LINUX
#endif // ATTACHMENTS_SUPPORTED
{"database", required_argument, nullptr, kOptionDatabase},
#if defined(OS_APPLE)
{"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
......@@ -692,14 +696,13 @@ int HandlerMain(int argc,
}
break;
}
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
defined(OS_ANDROID)
#if defined(ATTACHMENTS_SUPPORTED)
case kOptionAttachment: {
options.attachments.push_back(base::FilePath(
ToolSupport::CommandLineArgumentToFilePathStringType(optarg)));
break;
}
#endif // OS_WIN || OS_LINUX
#endif // ATTACHMENTS_SUPPORTED
case kOptionDatabase: {
options.database = base::FilePath(
ToolSupport::CommandLineArgumentToFilePathStringType(optarg));
......@@ -1012,9 +1015,9 @@ int HandlerMain(int argc,
database.get(),
static_cast<CrashReportUploadThread*>(upload_thread.Get()),
&options.annotations,
#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
#if defined(ATTACHMENTS_SUPPORTED)
&options.attachments,
#endif // OS_WIN || OS_LINUX
#endif // ATTACHMENTS_SUPPORTED
#if defined(OS_ANDROID)
options.write_minidump_to_database,
options.write_minidump_to_log,
......
......@@ -80,17 +80,16 @@ bool CaptureSnapshot(
return false;
}
auto annotations_whitelist = std::make_unique<std::vector<std::string>>();
auto memory_range_whitelist =
auto allowed_annotations = std::make_unique<std::vector<std::string>>();
auto allowed_memory_ranges =
std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>();
if (!ReadAnnotationsWhitelist(
if (!ReadAllowedAnnotations(range,
sanitization_info.allowed_annotations_address,
allowed_annotations.get()) ||
!ReadAllowedMemoryRanges(
range,
sanitization_info.annotations_whitelist_address,
annotations_whitelist.get()) ||
!ReadMemoryRangeWhitelist(
range,
sanitization_info.memory_range_whitelist_address,
memory_range_whitelist.get())) {
sanitization_info.allowed_memory_ranges_address,
allowed_memory_ranges.get())) {
Metrics::ExceptionCaptureResult(
Metrics::CaptureResult::kSanitizationInitializationFailed);
return false;
......@@ -99,10 +98,10 @@ bool CaptureSnapshot(
std::unique_ptr<ProcessSnapshotSanitized> sanitized(
new ProcessSnapshotSanitized());
if (!sanitized->Initialize(process_snapshot.get(),
sanitization_info.annotations_whitelist_address
? std::move(annotations_whitelist)
sanitization_info.allowed_annotations_address
? std::move(allowed_annotations)
: nullptr,
std::move(memory_range_whitelist),
std::move(allowed_memory_ranges),
sanitization_info.target_module_address,
sanitization_info.sanitize_stacks)) {
Metrics::ExceptionCaptureResult(
......
......@@ -27,7 +27,7 @@ namespace internal {
//! another MemorySnapshot.
//!
//! This class redacts all data from the wrapped MemorySnapshot unless:
//! 1. The data is pointer aligned and points into a whitelisted address range.
//! 1. The data is pointer aligned and points into an allowed address range.
//! 2. The data is pointer aligned and is a small integer.
class MemorySnapshotSanitized final : public MemorySnapshot {
public:
......@@ -41,7 +41,7 @@ class MemorySnapshotSanitized final : public MemorySnapshot {
//! \brief Constructs this object.
//!
//! \param[in] snapshot The MemorySnapshot to sanitize.
//! \param[in] ranges A set of whitelisted address ranges.
//! \param[in] ranges A set of allowed address ranges.
//! \param[in] is_64_bit `true` if this memory is for a 64-bit process.
MemorySnapshotSanitized(const MemorySnapshot* snapshot,
RangeSet* ranges,
......
......@@ -19,9 +19,9 @@ namespace internal {
namespace {
bool KeyIsInWhitelist(const std::string& name,
const std::vector<std::string>& whitelist) {
for (const auto& key : whitelist) {
bool KeyIsAllowed(const std::string& name,
const std::vector<std::string>& allowed_keys) {
for (const auto& key : allowed_keys) {
if (name == key) {
return true;
}
......@@ -33,8 +33,8 @@ bool KeyIsInWhitelist(const std::string& name,
ModuleSnapshotSanitized::ModuleSnapshotSanitized(
const ModuleSnapshot* snapshot,
const std::vector<std::string>* annotations_whitelist)
: snapshot_(snapshot), annotations_whitelist_(annotations_whitelist) {}
const std::vector<std::string>* allowed_annotations)
: snapshot_(snapshot), allowed_annotations_(allowed_annotations) {}
ModuleSnapshotSanitized::~ModuleSnapshotSanitized() = default;
......@@ -96,9 +96,9 @@ std::map<std::string, std::string>
ModuleSnapshotSanitized::AnnotationsSimpleMap() const {
std::map<std::string, std::string> annotations =
snapshot_->AnnotationsSimpleMap();
if (annotations_whitelist_) {
if (allowed_annotations_) {
for (auto kv = annotations.begin(); kv != annotations.end(); ++kv) {
if (!KeyIsInWhitelist(kv->first, *annotations_whitelist_)) {
if (!KeyIsAllowed(kv->first, *allowed_annotations_)) {
annotations.erase(kv);
}
}
......@@ -109,14 +109,14 @@ ModuleSnapshotSanitized::AnnotationsSimpleMap() const {
std::vector<AnnotationSnapshot> ModuleSnapshotSanitized::AnnotationObjects()
const {
std::vector<AnnotationSnapshot> annotations = snapshot_->AnnotationObjects();
if (annotations_whitelist_) {
std::vector<AnnotationSnapshot> whitelisted;
if (allowed_annotations_) {
std::vector<AnnotationSnapshot> allowed;
for (const auto& anno : annotations) {
if (KeyIsInWhitelist(anno.name, *annotations_whitelist_)) {
whitelisted.push_back(anno);
if (KeyIsAllowed(anno.name, *allowed_annotations_)) {
allowed.push_back(anno);
}
}
annotations.swap(whitelisted);
annotations.swap(allowed);
}
return annotations;
}
......
......@@ -31,12 +31,11 @@ class ModuleSnapshotSanitized final : public ModuleSnapshot {
//! \brief Constructs this object.
//!
//! \param[in] snapshot The ModuleSnapshot to sanitize.
//! \param[in] annotations_whitelist A list of annotation names to allow to be
//! \param[in] allowed_annotations A list of annotation names to allow to be
//! returned by AnnotationsSimpleMap() or AnnotationObjects(). If
//! `nullptr`, all annotations will be returned.
ModuleSnapshotSanitized(
const ModuleSnapshot* snapshot,
const std::vector<std::string>* annotations_whitelist);
ModuleSnapshotSanitized(const ModuleSnapshot* snapshot,
const std::vector<std::string>* allowed_annotations);
~ModuleSnapshotSanitized() override;
// ModuleSnapshot:
......@@ -65,7 +64,7 @@ class ModuleSnapshotSanitized final : public ModuleSnapshot {
private:
const ModuleSnapshot* snapshot_;
const std::vector<std::string>* annotations_whitelist_;
const std::vector<std::string>* allowed_annotations_;
DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotSanitized);
};
......
......@@ -84,14 +84,14 @@ ProcessSnapshotSanitized::~ProcessSnapshotSanitized() = default;
bool ProcessSnapshotSanitized::Initialize(
const ProcessSnapshot* snapshot,
std::unique_ptr<const std::vector<std::string>> annotations_whitelist,
std::unique_ptr<const std::vector<std::string>> allowed_annotations,
std::unique_ptr<const std::vector<std::pair<VMAddress, VMAddress>>>
memory_range_whitelist,
allowed_memory_ranges,
VMAddress target_module_address,
bool sanitize_stacks) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
snapshot_ = snapshot;
annotations_whitelist_ = std::move(annotations_whitelist);
allowed_annotations_ = std::move(allowed_annotations);
sanitize_stacks_ = sanitize_stacks;
if (target_module_address) {
......@@ -139,10 +139,10 @@ bool ProcessSnapshotSanitized::Initialize(
}
}
if (annotations_whitelist_) {
if (allowed_annotations_) {
for (const auto module : snapshot_->Modules()) {
modules_.emplace_back(std::make_unique<internal::ModuleSnapshotSanitized>(
module, annotations_whitelist_.get()));
module, allowed_annotations_.get()));
}
}
......@@ -159,7 +159,7 @@ bool ProcessSnapshotSanitized::Initialize(
}
}
process_memory_.Initialize(snapshot_->Memory(), memory_range_whitelist.get());
process_memory_.Initialize(snapshot_->Memory(), allowed_memory_ranges.get());
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
......@@ -227,7 +227,7 @@ std::vector<const ThreadSnapshot*> ProcessSnapshotSanitized::Threads() const {
std::vector<const ModuleSnapshot*> ProcessSnapshotSanitized::Modules() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!annotations_whitelist_) {
if (!allowed_annotations_) {
return snapshot_->Modules();
}
......
......@@ -47,10 +47,10 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot {
//! this object.
//!
//! \param[in] snapshot The ProcessSnapshot to sanitize.
//! \param[in] annotations_whitelist A list of annotations names to allow to
//! \param[in] allowed_annotations A list of annotations names to allow to
//! be returned by AnnotationsSimpleMap() or from this object's module
//! snapshots. If `nullptr`, all annotations will be returned.
//! \param[in] memory_range_whitelist A list of memory ranges to allow to be
//! \param[in] allowed_memory_ranges A list of memory ranges to allow to be
//! accessible via Memory(), or `nullptr` to allow all ranges.
//! \param[in] target_module_address An address in the target process'
//! address space within the bounds of a module to target. If the
......@@ -65,9 +65,9 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot {
//! should be filtered entirely. Otherwise `true`.
bool Initialize(
const ProcessSnapshot* snapshot,
std::unique_ptr<const std::vector<std::string>> annotations_whitelist,
std::unique_ptr<const std::vector<std::string>> allowed_annotations,
std::unique_ptr<const std::vector<std::pair<VMAddress, VMAddress>>>
memory_range_whitelist,
allowed_memory_ranges,
VMAddress target_module_address,
bool sanitize_stacks);
......@@ -93,7 +93,7 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot {
const ProcessMemory* Memory() const override;
private:
// Only used when annotations_whitelist_ != nullptr.
// Only used when allowed_annotations_ != nullptr.
std::vector<std::unique_ptr<internal::ModuleSnapshotSanitized>> modules_;
// Only used when sanitize_stacks_ == true.
......@@ -102,7 +102,7 @@ class ProcessSnapshotSanitized final : public ProcessSnapshot {
RangeSet address_ranges_;
const ProcessSnapshot* snapshot_;
ProcessMemorySanitized process_memory_;
std::unique_ptr<const std::vector<std::string>> annotations_whitelist_;
std::unique_ptr<const std::vector<std::string>> allowed_annotations_;
bool sanitize_stacks_;
InitializationStateDcheck initialized_;
......
......@@ -74,10 +74,10 @@ class ExceptionGenerator {
DISALLOW_COPY_AND_ASSIGN(ExceptionGenerator);
};
constexpr char kWhitelistedAnnotationName[] = "name_of_whitelisted_anno";
constexpr char kWhitelistedAnnotationValue[] = "some_value";
constexpr char kNonWhitelistedAnnotationName[] = "non_whitelisted_anno";
constexpr char kNonWhitelistedAnnotationValue[] = "private_annotation";
constexpr char kAllowedAnnotationName[] = "name_of_allowed_anno";
constexpr char kAllowedAnnotationValue[] = "some_value";
constexpr char kNonAllowedAnnotationName[] = "non_allowed_anno";
constexpr char kNonAllowedAnnotationValue[] = "private_annotation";
constexpr char kSensitiveStackData[] = "sensitive_stack_data";
struct ChildTestAddresses {
......@@ -92,13 +92,11 @@ void ChildTestFunction() {
FileHandle in = StdioFileHandle(StdioStream::kStandardInput);
FileHandle out = StdioFileHandle(StdioStream::kStandardOutput);
static StringAnnotation<32> whitelisted_annotation(
kWhitelistedAnnotationName);
whitelisted_annotation.Set(kWhitelistedAnnotationValue);
static StringAnnotation<32> allowed_annotation(kAllowedAnnotationName);
allowed_annotation.Set(kAllowedAnnotationValue);
static StringAnnotation<32> non_whitelisted_annotation(
kNonWhitelistedAnnotationName);
non_whitelisted_annotation.Set(kNonWhitelistedAnnotationValue);
static StringAnnotation<32> non_allowed_annotation(kNonAllowedAnnotationName);
non_allowed_annotation.Set(kNonAllowedAnnotationValue);
char string_data[strlen(kSensitiveStackData) + 1];
strcpy(string_data, kSensitiveStackData);
......@@ -126,39 +124,39 @@ CRASHPAD_CHILD_TEST_MAIN(ChildToBeSanitized) {
}
void ExpectAnnotations(ProcessSnapshot* snapshot, bool sanitized) {
bool found_whitelisted = false;
bool found_non_whitelisted = false;
bool found_allowed = false;
bool found_non_allowed = false;
for (auto module : snapshot->Modules()) {
for (const auto& anno : module->AnnotationObjects()) {
if (anno.name == kWhitelistedAnnotationName) {
found_whitelisted = true;
} else if (anno.name == kNonWhitelistedAnnotationName) {
found_non_whitelisted = true;
if (anno.name == kAllowedAnnotationName) {
found_allowed = true;
} else if (anno.name == kNonAllowedAnnotationName) {
found_non_allowed = true;
}
}
}
EXPECT_TRUE(found_whitelisted);
EXPECT_TRUE(found_allowed);
if (sanitized) {
EXPECT_FALSE(found_non_whitelisted);
EXPECT_FALSE(found_non_allowed);
} else {
EXPECT_TRUE(found_non_whitelisted);
EXPECT_TRUE(found_non_allowed);
}
}
void ExpectProcessMemory(ProcessSnapshot* snapshot,
VMAddress whitelisted_byte,
VMAddress allowed_byte,
bool sanitized) {
auto memory = snapshot->Memory();
char out;
EXPECT_TRUE(memory->Read(whitelisted_byte, 1, &out));
EXPECT_TRUE(memory->Read(allowed_byte, 1, &out));
bool unwhitelisted_read = memory->Read(whitelisted_byte + 1, 1, &out);
bool disallowed_read = memory->Read(allowed_byte + 1, 1, &out);
if (sanitized) {
EXPECT_FALSE(unwhitelisted_read);
EXPECT_FALSE(disallowed_read);
} else {
EXPECT_TRUE(unwhitelisted_read);
EXPECT_TRUE(disallowed_read);
}
}
......@@ -272,18 +270,18 @@ class SanitizeTest : public MultiprocessExec {
addrs.string_address,
/* sanitized= */ false);
auto annotations_whitelist = std::make_unique<std::vector<std::string>>();
annotations_whitelist->push_back(kWhitelistedAnnotationName);
auto allowed_annotations = std::make_unique<std::vector<std::string>>();
allowed_annotations->push_back(kAllowedAnnotationName);
auto memory_ranges_whitelist =
auto allowed_memory_ranges =
std::make_unique<std::vector<std::pair<VMAddress, VMAddress>>>();
memory_ranges_whitelist->push_back(
allowed_memory_ranges->push_back(
std::make_pair(addrs.string_address, addrs.string_address + 1));
ProcessSnapshotSanitized sanitized;
ASSERT_TRUE(sanitized.Initialize(&snapshot,
std::move(annotations_whitelist),
std::move(memory_ranges_whitelist),
std::move(allowed_annotations),
std::move(allowed_memory_ranges),
addrs.module_address,
true));
......
......@@ -24,18 +24,18 @@ namespace crashpad {
namespace {
template <typename Pointer>
bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::string>* whitelist) {
if (!whitelist_address) {
bool ReadAllowedAnnotations(const ProcessMemoryRange& memory,
VMAddress list_address,
std::vector<std::string>* allowed_annotations) {
if (!list_address) {
return true;
}
std::vector<std::string> local_whitelist;
std::vector<std::string> local_allowed_annotations;
Pointer name_address;
while (memory.Read(whitelist_address, sizeof(name_address), &name_address)) {
while (memory.Read(list_address, sizeof(name_address), &name_address)) {
if (!name_address) {
whitelist->swap(local_whitelist);
allowed_annotations->swap(local_allowed_annotations);
return true;
}
......@@ -44,8 +44,8 @@ bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
name_address, Annotation::kNameMaxLength, &name)) {
return false;
}
local_whitelist.push_back(name);
whitelist_address += sizeof(Pointer);
local_allowed_annotations.push_back(name);
list_address += sizeof(Pointer);
}
return false;
......@@ -53,27 +53,27 @@ bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
} // namespace
bool ReadAnnotationsWhitelist(const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::string>* whitelist) {
return memory.Is64Bit() ? ReadAnnotationsWhitelist<uint64_t>(
memory, whitelist_address, whitelist)
: ReadAnnotationsWhitelist<uint32_t>(
memory, whitelist_address, whitelist);
bool ReadAllowedAnnotations(const ProcessMemoryRange& memory,
VMAddress list_address,
std::vector<std::string>* allowed_annotations) {
return memory.Is64Bit() ? ReadAllowedAnnotations<uint64_t>(
memory, list_address, allowed_annotations)
: ReadAllowedAnnotations<uint32_t>(
memory, list_address, allowed_annotations);
}
bool ReadMemoryRangeWhitelist(
bool ReadAllowedMemoryRanges(
const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::pair<VMAddress, VMAddress>>* whitelist) {
whitelist->clear();
if (!whitelist_address) {
VMAddress list_address,
std::vector<std::pair<VMAddress, VMAddress>>* allowed_memory_ranges) {
allowed_memory_ranges->clear();
if (!list_address) {
return true;
}
SanitizationMemoryRangeWhitelist list;
if (!memory.Read(whitelist_address, sizeof(list), &list)) {
LOG(ERROR) << "Failed to read memory range whitelist.";
SanitizationAllowedMemoryRanges list;
if (!memory.Read(list_address, sizeof(list), &list)) {
LOG(ERROR) << "Failed to read allowed memory ranges";
return false;
}
......@@ -84,32 +84,32 @@ bool ReadMemoryRangeWhitelist(
// An upper bound of entries that we never expect to see more than.
constexpr size_t kMaxListSize = 256;
if (list.size > kMaxListSize) {
LOG(ERROR) << "Whitelist exceeded maximum, size=" << list.size;
LOG(ERROR) << "list exceeded maximum, size=" << list.size;
return false;
}
std::vector<SanitizationMemoryRangeWhitelist::Range> ranges(list.size);
std::vector<SanitizationAllowedMemoryRanges::Range> ranges(list.size);
if (!memory.Read(list.entries, sizeof(ranges[0]) * list.size,
ranges.data())) {
LOG(ERROR) << "Failed to read memory range whitelist entries.";
LOG(ERROR) << "Failed to read allowed memory ranges";
return false;
}
const VMAddress vm_max = memory.Is64Bit()
? std::numeric_limits<uint64_t>::max()
: std::numeric_limits<uint32_t>::max();
std::vector<std::pair<VMAddress, VMAddress>> local_whitelist;
for (size_t i = 0; i < list.size; i++) {
std::vector<std::pair<VMAddress, VMAddress>> local_allowed_memory_ranges;
for (size_t i = 0; i < list.size; ++i) {
if (ranges[i].base > vm_max || ranges[i].length > vm_max - ranges[i].base) {
LOG(ERROR) << "Invalid memory range whitelist entry base="
<< ranges[i].base << " length=" << ranges[i].length;
LOG(ERROR) << "Invalid range: base=" << ranges[i].base
<< " length=" << ranges[i].length;
return false;
}
local_whitelist.emplace_back(ranges[i].base,
ranges[i].base + ranges[i].length);
local_allowed_memory_ranges.emplace_back(ranges[i].base,
ranges[i].base + ranges[i].length);
}
whitelist->swap(local_whitelist);
allowed_memory_ranges->swap(local_allowed_memory_ranges);
return true;
}
......
......@@ -35,9 +35,9 @@ namespace crashpad {
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;
//! names of allowed annotations. This value is 0 if all annotations are
//! allowed.
VMAddress allowed_annotations_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
......@@ -47,17 +47,17 @@ struct SanitizationInformation {
VMAddress target_module_address;
//! \brief The address in the client process' address space of a
//! a \a SanitizationMemoryRangeWhitelist, a list of whitelisted address
//! ranges allowed to be accessed by ProcessMemorySanitized. This value
//! is 0 if no memory is allowed to be read using ProcessMemorySanitized.
VMAddress memory_range_whitelist_address;
//! \a SanitizationAllowedMemoryRanges, a list of address ranges allowed
//! to be accessed by ProcessMemorySanitized. This value is 0 if no memory
//! is allowed to be read using ProcessMemorySanitized.
VMAddress allowed_memory_ranges_address;
//! \brief Non-zero if stacks should be sanitized for possible PII.
uint8_t sanitize_stacks;
};
//! \brief Describes a list of white listed memory ranges.
struct SanitizationMemoryRangeWhitelist {
//! \brief Describes a list of allowed memory ranges.
struct SanitizationAllowedMemoryRanges {
//! \brief Describes a range of memory.
struct Range {
VMAddress base;
......@@ -71,30 +71,30 @@ struct SanitizationMemoryRangeWhitelist {
#pragma pack(pop)
//! \brief Reads an annotations whitelist from another process.
//! \brief Reads a list of allowed annotations 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
//! \param[in] list_address The address in the target process' address space of
//! a nullptr terminated array of NUL-terminated strings.
//! \param[out] allowed_annotations The list 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);
bool ReadAllowedAnnotations(const ProcessMemoryRange& memory,
VMAddress list_address,
std::vector<std::string>* allowed_annotations);
//! \brief Reads a memory range whitelist from another process.
//! \brief Reads a list of allowed memory ranges 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 A list of whitelisted memory regions, valid only if
//! this function returns `true`.
//! \param[in] list_address The address in the target process' address space of
//! a nullptr terminated array of NUL-terminated strings.
//! \param[out] allowed_memory_ranges A list of allowed memory regions, valid
//! only if this function returns `true`.
//! \return `true` on success, `false` on failure with a message logged.
bool ReadMemoryRangeWhitelist(
bool ReadAllowedMemoryRanges(
const ProcessMemoryRange& memory,
VMAddress whitelist_address,
std::vector<std::pair<VMAddress, VMAddress>>* whitelist);
VMAddress list_address,
std::vector<std::pair<VMAddress, VMAddress>>* allowed_memory_ranges);
} // namespace crashpad
......
......@@ -24,7 +24,7 @@ namespace crashpad {
namespace test {
namespace {
class WhitelistTest : public testing::Test {
class AllowedAnnotationsTest : public testing::Test {
public:
void SetUp() override {
ASSERT_TRUE(memory_.Initialize(getpid()));
......@@ -36,33 +36,34 @@ class WhitelistTest : public testing::Test {
}
protected:
bool ReadWhitelist(const char* const* address) {
return ReadAnnotationsWhitelist(
range_, FromPointerCast<VMAddress>(address), &whitelist_);
bool DoReadAllowedAnnotations(const char* const* address) {
return ReadAllowedAnnotations(
range_, FromPointerCast<VMAddress>(address), &allowed_annotations_);
}
ProcessMemoryLinux memory_;
ProcessMemoryRange range_;
std::vector<std::string> whitelist_;
std::vector<std::string> allowed_annotations_;
};
const char* const kEmptyWhitelist[] = {nullptr};
const char* const kEmptyAllowedAnnotations[] = {nullptr};
TEST_F(WhitelistTest, EmptyWhitelist) {
ASSERT_TRUE(ReadWhitelist(kEmptyWhitelist));
EXPECT_EQ(whitelist_, std::vector<std::string>());
TEST_F(AllowedAnnotationsTest, EmptyAllowedAnnotations) {
ASSERT_TRUE(DoReadAllowedAnnotations(kEmptyAllowedAnnotations));
EXPECT_EQ(allowed_annotations_, std::vector<std::string>());
}
const char* const kNonEmptyWhitelist[] = {"string1",
"another_string",
"",
nullptr};
const char* const kNonEmptyAllowedAnnotations[] = {"string1",
"another_string",
"",
nullptr};
TEST_F(WhitelistTest, NonEmptyWhitelist) {
ASSERT_TRUE(ReadWhitelist(kNonEmptyWhitelist));
ASSERT_EQ(whitelist_.size(), base::size(kNonEmptyWhitelist) - 1);
for (size_t index = 0; index < base::size(kNonEmptyWhitelist) - 1; ++index) {
EXPECT_EQ(whitelist_[index], kNonEmptyWhitelist[index]);
TEST_F(AllowedAnnotationsTest, NonEmptyAllowedAnnotations) {
ASSERT_TRUE(DoReadAllowedAnnotations(kNonEmptyAllowedAnnotations));
ASSERT_EQ(allowed_annotations_.size(),
base::size(kNonEmptyAllowedAnnotations) - 1);
for (size_t index = 0; index < allowed_annotations_.size(); ++index) {
EXPECT_EQ(allowed_annotations_[index], kNonEmptyAllowedAnnotations[index]);
}
}
......
......@@ -28,17 +28,17 @@
namespace crashpad {
ProcessMemorySanitized::ProcessMemorySanitized()
: ProcessMemory(), memory_(nullptr), whitelist_() {}
: ProcessMemory(), memory_(nullptr), allowed_ranges_() {}
ProcessMemorySanitized::~ProcessMemorySanitized() {}
bool ProcessMemorySanitized::Initialize(
const ProcessMemory* memory,
const std::vector<std::pair<VMAddress, VMAddress>>* whitelist) {
const std::vector<std::pair<VMAddress, VMAddress>>* allowed_ranges) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
memory_ = memory;
if (whitelist)
whitelist_ = *whitelist;
if (allowed_ranges)
allowed_ranges_ = *allowed_ranges;
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
......@@ -49,7 +49,7 @@ ssize_t ProcessMemorySanitized::ReadUpTo(VMAddress address,
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
VMAddress end = address + size;
for (auto&& entry : whitelist_) {
for (auto&& entry : allowed_ranges_) {
if (address >= entry.first && address < entry.second &&
end >= entry.first && end <= entry.second) {
return memory_->ReadUpTo(address, size, buffer);
......@@ -57,7 +57,7 @@ ssize_t ProcessMemorySanitized::ReadUpTo(VMAddress address,
}
DLOG(ERROR)
<< "ProcessMemorySanitized failed to read unwhitelisted region. address="
<< "ProcessMemorySanitized failed to read disallowed region. address="
<< address << " size=" << size;
return 0;
}
......
......@@ -34,25 +34,25 @@ class ProcessMemorySanitized final : public ProcessMemory {
~ProcessMemorySanitized();
//! \brief Initializes this object to read memory from the underlying
//! \a memory object if the memory range is in the provided \a whitelist.
//! \a memory object if the memory range is in \a allowed_ranges.
//!
//! This method must be called successfully prior to calling any other method
//! in this class.
//!
//! \param[in] memory The memory object to read whitelisted regions from.
//! \param[in] whitelist A whitelist of memory regions.
//! \param[in] memory The memory object to read memory from.
//! \param[in] allowed_ranges A list of allowed memory ranges.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool Initialize(
const ProcessMemory* memory,
const std::vector<std::pair<VMAddress, VMAddress>>* whitelist);
const std::vector<std::pair<VMAddress, VMAddress>>* allowed_ranges);
private:
ssize_t ReadUpTo(VMAddress address, size_t size, void* buffer) const override;
const ProcessMemory* memory_;
InitializationStateDcheck initialized_;
std::vector<std::pair<VMAddress, VMAddress>> whitelist_;
std::vector<std::pair<VMAddress, VMAddress>> allowed_ranges_;
DISALLOW_COPY_AND_ASSIGN(ProcessMemorySanitized);
};
......
......@@ -23,7 +23,7 @@ namespace crashpad {
namespace test {
namespace {
TEST(ProcessMemorySanitized, DenyOnEmptyWhitelist) {
TEST(ProcessMemorySanitized, DenyDisallowedMemory) {
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
......@@ -34,25 +34,25 @@ TEST(ProcessMemorySanitized, DenyOnEmptyWhitelist) {
san_null.Initialize(&memory, nullptr);
EXPECT_FALSE(san_null.Read(FromPointerCast<VMAddress>(&c), 1, &out));
std::vector<std::pair<VMAddress, VMAddress>> whitelist;
ProcessMemorySanitized san_blank;
san_blank.Initialize(&memory, &whitelist);
EXPECT_FALSE(san_blank.Read(FromPointerCast<VMAddress>(&c), 1, &out));
std::vector<std::pair<VMAddress, VMAddress>> allowed_memory;
ProcessMemorySanitized san_empty;
san_empty.Initialize(&memory, &allowed_memory);
EXPECT_FALSE(san_empty.Read(FromPointerCast<VMAddress>(&c), 1, &out));
}
TEST(ProcessMemorySanitized, WhitelistingWorks) {
TEST(ProcessMemorySanitized, AllowedMemory) {
ProcessMemoryNative memory;
ASSERT_TRUE(memory.Initialize(GetSelfProcess()));
char str[4] = "ABC";
char out[4];
std::vector<std::pair<VMAddress, VMAddress>> whitelist;
whitelist.push_back(std::make_pair(FromPointerCast<VMAddress>(str + 1),
FromPointerCast<VMAddress>(str + 2)));
std::vector<std::pair<VMAddress, VMAddress>> allowed_memory;
allowed_memory.push_back(std::make_pair(FromPointerCast<VMAddress>(str + 1),
FromPointerCast<VMAddress>(str + 2)));
ProcessMemorySanitized sanitized;
sanitized.Initialize(&memory, &whitelist);
sanitized.Initialize(&memory, &allowed_memory);
EXPECT_FALSE(sanitized.Read(FromPointerCast<VMAddress>(str), 1, &out));
EXPECT_TRUE(sanitized.Read(FromPointerCast<VMAddress>(str + 1), 1, &out));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment