crashpad/client/crashpad_client_linux_test.cc

789 lines
25 KiB
C++
Raw Normal View History

// Copyright 2018 The Crashpad Authors
//
// 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 "client/crashpad_client.h"
#include <dlfcn.h>
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
#include <sys/utsname.h>
#include <unistd.h>
#include "base/check_op.h"
#include "base/notreached.h"
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#include "build/build_config.h"
#include "client/annotation.h"
#include "client/annotation_list.h"
#include "client/crash_report_database.h"
#include "client/crashpad_info.h"
#include "client/simulate_crash.h"
#include "gtest/gtest.h"
#include "snapshot/annotation_snapshot.h"
#include "snapshot/minidump/process_snapshot_minidump.h"
#include "snapshot/sanitized/sanitization_information.h"
#include "test/errors.h"
#include "test/multiprocess.h"
#include "test/multiprocess_exec.h"
#include "test/scoped_temp_dir.h"
#include "test/test_paths.h"
#include "util/file/file_io.h"
#include "util/file/filesystem.h"
#include "util/linux/exception_handler_client.h"
#include "util/linux/exception_information.h"
#include "util/linux/socket.h"
#include "util/misc/address_sanitizer.h"
#include "util/misc/address_types.h"
#include "util/misc/from_pointer_cast.h"
#include "util/misc/memory_sanitizer.h"
#include "util/posix/scoped_mmap.h"
#include "util/posix/signals.h"
#include "util/thread/thread.h"
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_ANDROID)
#include <android/set_abort_message.h>
#include "dlfcn_internal.h"
// Normally this comes from set_abort_message.h, but only at API level 21.
extern "C" void android_set_abort_message(const char* msg)
__attribute__((weak));
#endif
namespace crashpad {
namespace test {
namespace {
enum class CrashType : uint32_t {
kSimulated,
kBuiltinTrap,
kInfiniteRecursion,
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
kSegvWithTagBits,
// kFakeSegv is meant to simulate a MTE segv error.
kFakeSegv,
};
struct StartHandlerForSelfTestOptions {
bool start_handler_at_crash;
bool set_first_chance_handler;
bool set_last_chance_handler;
bool crash_non_main_thread;
bool client_uses_signals;
bool gather_indirectly_referenced_memory;
CrashType crash_type;
};
class StartHandlerForSelfTest
: public testing::TestWithParam<
std::tuple<bool, bool, bool, bool, bool, bool, CrashType>> {
public:
StartHandlerForSelfTest() = default;
StartHandlerForSelfTest(const StartHandlerForSelfTest&) = delete;
StartHandlerForSelfTest& operator=(const StartHandlerForSelfTest&) = delete;
~StartHandlerForSelfTest() = default;
void SetUp() override {
// MSAN requires that padding bytes have been initialized for structs that
// are written to files.
memset(&options_, 0, sizeof(options_));
std::tie(options_.start_handler_at_crash,
options_.set_first_chance_handler,
options_.set_last_chance_handler,
options_.crash_non_main_thread,
options_.client_uses_signals,
options_.gather_indirectly_referenced_memory,
options_.crash_type) = GetParam();
}
const StartHandlerForSelfTestOptions& Options() const { return options_; }
private:
StartHandlerForSelfTestOptions options_;
};
bool InstallHandler(CrashpadClient* client,
bool start_at_crash,
const base::FilePath& handler_path,
const base::FilePath& database_path,
const std::vector<base::FilePath>& attachments) {
return start_at_crash
? client->StartHandlerAtCrash(handler_path,
database_path,
base::FilePath(),
"",
std::map<std::string, std::string>(),
std::vector<std::string>(),
attachments)
: client->StartHandler(handler_path,
database_path,
base::FilePath(),
"",
std::map<std::string, std::string>(),
std::vector<std::string>(),
false,
false,
attachments);
}
constexpr char kTestAnnotationName[] = "name_of_annotation";
constexpr char kTestAnnotationValue[] = "value_of_annotation";
constexpr char kTestAttachmentName[] = "test_attachment";
constexpr char kTestAttachmentContent[] = "attachment_content";
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_ANDROID)
constexpr char kTestAbortMessage[] = "test abort message";
#endif
void ValidateAttachment(const CrashReportDatabase::UploadReport* report) {
auto attachments = report->GetAttachments();
ASSERT_EQ(attachments.size(), 1u);
char buf[sizeof(kTestAttachmentContent)];
attachments.at(kTestAttachmentName)->Read(buf, sizeof(buf));
ASSERT_EQ(memcmp(kTestAttachmentContent, buf, sizeof(kTestAttachmentContent)),
0);
}
void ValidateExtraMemory(const StartHandlerForSelfTestOptions& options,
const ProcessSnapshotMinidump& minidump) {
// Verify that if we have an exception, then the code around the instruction
// pointer is included in the extra memory.
const ExceptionSnapshot* exception = minidump.Exception();
if (exception == nullptr)
return;
uint64_t pc = exception->Context()->InstructionPointer();
std::vector<const MemorySnapshot*> snippets = minidump.ExtraMemory();
bool pc_found = false;
for (const MemorySnapshot* snippet : snippets) {
uint64_t start = snippet->Address();
uint64_t end = start + snippet->Size();
if (pc >= start && pc < end) {
pc_found = true;
break;
}
}
EXPECT_EQ(pc_found, options.gather_indirectly_referenced_memory);
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
if (options.crash_type == CrashType::kSegvWithTagBits) {
EXPECT_EQ(exception->ExceptionAddress(), 0xefull << 56);
}
}
void ValidateDump(const StartHandlerForSelfTestOptions& options,
const CrashReportDatabase::UploadReport* report) {
ProcessSnapshotMinidump minidump_snapshot;
ASSERT_TRUE(minidump_snapshot.Initialize(report->Reader()));
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_ANDROID)
// This part of the test requires Q. The API level on Q devices will be 28
// until the API is finalized, so we can't check API level yet. For now, test
// for the presence of a libc symbol which was introduced in Q.
if (crashpad::internal::Dlsym(RTLD_DEFAULT, "android_fdsan_close_with_tag")) {
const auto& annotations = minidump_snapshot.AnnotationsSimpleMap();
auto abort_message = annotations.find("abort_message");
ASSERT_NE(annotations.end(), abort_message);
EXPECT_EQ(kTestAbortMessage, abort_message->second);
}
#endif
ValidateAttachment(report);
ValidateExtraMemory(options, minidump_snapshot);
for (const ModuleSnapshot* module : minidump_snapshot.Modules()) {
for (const AnnotationSnapshot& annotation : module->AnnotationObjects()) {
if (static_cast<Annotation::Type>(annotation.type) !=
Annotation::Type::kString) {
continue;
}
if (annotation.name == kTestAnnotationName) {
std::string value(
reinterpret_cast<const char*>(annotation.value.data()),
annotation.value.size());
EXPECT_EQ(value, kTestAnnotationValue);
return;
}
}
}
ADD_FAILURE();
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winfinite-recursion"
// Clang (masquerading as gcc) is too smart, and removes the recursion
// otherwise. May need to change if either clang or another compiler becomes
// smarter.
#if defined(COMPILER_GCC)
__attribute__((noinline))
#endif
#if defined(__clang__)
__attribute__((optnone))
#endif
int RecurseInfinitely(int* ptr) {
int buf[1 << 20];
return *ptr + RecurseInfinitely(buf);
}
#pragma clang diagnostic pop
sigjmp_buf do_crash_sigjmp_env;
bool HandleCrashSuccessfully(int, siginfo_t*, ucontext_t*) {
siglongjmp(do_crash_sigjmp_env, 1);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code-return"
return true;
#pragma clang diagnostic pop
}
bool HandleCrashSuccessfullyAfterReporting(int, siginfo_t*, ucontext_t*) {
return true;
}
void DoCrash(const StartHandlerForSelfTestOptions& options,
CrashpadClient* client) {
if (sigsetjmp(do_crash_sigjmp_env, 1) != 0) {
return;
}
switch (options.crash_type) {
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
case CrashType::kSimulated: {
CRASHPAD_SIMULATE_CRASH();
break;
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
}
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
case CrashType::kBuiltinTrap: {
__builtin_trap();
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
}
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
case CrashType::kInfiniteRecursion: {
int val = 42;
exit(RecurseInfinitely(&val));
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
}
case CrashType::kSegvWithTagBits: {
volatile char* x = nullptr;
#ifdef __aarch64__
x += 0xefull << 56;
#endif // __aarch64__
*x;
break;
}
case CrashType::kFakeSegv: {
// With a regular SIGSEGV like null dereference, the signal gets reraised
// automatically, causing HandleOrReraiseSignal() to be called a second
// time, terminating the process with the signal regardless of the last
// chance handler.
raise(SIGSEGV);
break;
}
}
}
class ScopedAltSignalStack {
public:
ScopedAltSignalStack() = default;
ScopedAltSignalStack(const ScopedAltSignalStack&) = delete;
ScopedAltSignalStack& operator=(const ScopedAltSignalStack&) = delete;
~ScopedAltSignalStack() {
if (stack_mem_.is_valid()) {
stack_t stack;
stack.ss_flags = SS_DISABLE;
if (sigaltstack(&stack, nullptr) != 0) {
ADD_FAILURE() << ErrnoMessage("sigaltstack");
}
}
}
void Initialize() {
ScopedMmap local_stack_mem;
const size_t stack_size = MINSIGSTKSZ;
ASSERT_TRUE(local_stack_mem.ResetMmap(nullptr,
stack_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0));
stack_t stack;
stack.ss_sp = local_stack_mem.addr();
stack.ss_size = stack_size;
stack.ss_flags = 0;
ASSERT_EQ(sigaltstack(&stack, nullptr), 0) << ErrnoMessage("sigaltstack");
stack_mem_.ResetAddrLen(local_stack_mem.release(), stack_size);
}
private:
ScopedMmap stack_mem_;
};
class CrashThread : public Thread {
public:
CrashThread(const StartHandlerForSelfTestOptions& options,
CrashpadClient* client)
: client_signal_stack_(), options_(options), client_(client) {}
CrashThread(const CrashThread&) = delete;
CrashThread& operator=(const CrashThread&) = delete;
private:
void ThreadMain() override {
// It is only necessary to call InitializeSignalStackForThread() once, but
// should be harmless to call multiple times and durable against the client
// using sigaltstack() either before or after it is called.
CrashpadClient::InitializeSignalStackForThread();
if (options_.client_uses_signals) {
client_signal_stack_.Initialize();
}
CrashpadClient::InitializeSignalStackForThread();
DoCrash(options_, client_);
}
ScopedAltSignalStack client_signal_stack_;
const StartHandlerForSelfTestOptions& options_;
CrashpadClient* client_;
};
CRASHPAD_CHILD_TEST_MAIN(StartHandlerForSelfTestChild) {
FileHandle in = StdioFileHandle(StdioStream::kStandardInput);
VMSize temp_dir_length;
CheckedReadFileExactly(in, &temp_dir_length, sizeof(temp_dir_length));
std::string temp_dir(temp_dir_length, '\0');
CheckedReadFileExactly(in, &temp_dir[0], temp_dir_length);
StartHandlerForSelfTestOptions options;
CheckedReadFileExactly(in, &options, sizeof(options));
ScopedAltSignalStack client_signal_stack;
if (options.client_uses_signals) {
client_signal_stack.Initialize();
static Signals::OldActions old_actions;
static Signals::Handler client_handler =
[](int signo, siginfo_t* siginfo, void*) {
FileHandle out = StdioFileHandle(StdioStream::kStandardOutput);
char c = 0;
WriteFile(out, &c, sizeof(c));
Signals::RestoreHandlerAndReraiseSignalOnReturn(
siginfo, old_actions.ActionForSignal(signo));
};
CHECK(Signals::InstallCrashHandlers(
client_handler, SA_ONSTACK, &old_actions));
}
if (options.gather_indirectly_referenced_memory) {
CrashpadInfo::GetCrashpadInfo()->set_gather_indirectly_referenced_memory(
TriState::kEnabled, 1024 * 1024 * 4);
}
base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_handler"));
crashpad::AnnotationList::Register();
static StringAnnotation<32> test_annotation(kTestAnnotationName);
test_annotation.Set(kTestAnnotationValue);
const std::vector<base::FilePath> attachments = {
base::FilePath(temp_dir).Append(kTestAttachmentName)};
crashpad::CrashpadClient client;
if (!InstallHandler(&client,
options.start_handler_at_crash,
handler_path,
base::FilePath(temp_dir),
attachments)) {
return EXIT_FAILURE;
}
if (options.set_first_chance_handler) {
client.SetFirstChanceExceptionHandler(HandleCrashSuccessfully);
}
if (options.set_last_chance_handler) {
client.SetLastChanceExceptionHandler(HandleCrashSuccessfullyAfterReporting);
}
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_ANDROID)
if (android_set_abort_message) {
android_set_abort_message(kTestAbortMessage);
}
#endif
if (options.crash_non_main_thread) {
CrashThread thread(options, &client);
thread.Start();
thread.Join();
} else {
DoCrash(options, &client);
}
return EXIT_SUCCESS;
}
class StartHandlerForSelfInChildTest : public MultiprocessExec {
public:
StartHandlerForSelfInChildTest(const StartHandlerForSelfTestOptions& options)
: MultiprocessExec(), options_(options) {
SetChildTestMainFunction("StartHandlerForSelfTestChild");
if (!options.set_first_chance_handler) {
switch (options.crash_type) {
case CrashType::kSimulated:
// kTerminationNormal, EXIT_SUCCESS
break;
case CrashType::kBuiltinTrap:
SetExpectedChildTerminationBuiltinTrap();
break;
case CrashType::kInfiniteRecursion:
SetExpectedChildTermination(TerminationReason::kTerminationSignal,
SIGSEGV);
break;
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
case CrashType::kSegvWithTagBits:
SetExpectedChildTermination(TerminationReason::kTerminationSignal,
SIGSEGV);
break;
case CrashType::kFakeSegv:
if (!options.set_last_chance_handler) {
SetExpectedChildTermination(TerminationReason::kTerminationSignal,
SIGSEGV);
} else {
SetExpectedChildTermination(TerminationReason::kTerminationNormal,
EXIT_SUCCESS);
}
break;
}
}
}
StartHandlerForSelfInChildTest(const StartHandlerForSelfInChildTest&) =
delete;
StartHandlerForSelfInChildTest& operator=(
const StartHandlerForSelfInChildTest&) = delete;
private:
void MultiprocessParent() override {
ScopedTempDir temp_dir;
VMSize temp_dir_length = temp_dir.path().value().size();
ASSERT_TRUE(LoggingWriteFile(
WritePipeHandle(), &temp_dir_length, sizeof(temp_dir_length)));
ASSERT_TRUE(LoggingWriteFile(
WritePipeHandle(), temp_dir.path().value().data(), temp_dir_length));
ASSERT_TRUE(
LoggingWriteFile(WritePipeHandle(), &options_, sizeof(options_)));
FileWriter writer;
base::FilePath test_attachment_path =
temp_dir.path().Append(kTestAttachmentName);
bool is_created = writer.Open(test_attachment_path,
FileWriteMode::kCreateOrFail,
FilePermissions::kOwnerOnly);
ASSERT_TRUE(is_created);
writer.Write(kTestAttachmentContent, sizeof(kTestAttachmentContent));
writer.Close();
if (options_.client_uses_signals && !options_.set_first_chance_handler &&
options_.crash_type != CrashType::kSimulated &&
// The last chance handler will prevent the client handler from being
// called if crash type is kFakeSegv.
(!options_.set_last_chance_handler ||
options_.crash_type != CrashType::kFakeSegv)) {
// Wait for child's client signal handler.
char c;
EXPECT_TRUE(LoggingReadFileExactly(ReadPipeHandle(), &c, sizeof(c)));
}
// Wait for child to finish.
CheckedReadFileAtEOF(ReadPipeHandle());
auto database = CrashReportDatabase::Initialize(temp_dir.path());
ASSERT_TRUE(database);
std::vector<CrashReportDatabase::Report> reports;
ASSERT_EQ(database->GetCompletedReports(&reports),
CrashReportDatabase::kNoError);
EXPECT_EQ(reports.size(), 0u);
reports.clear();
ASSERT_EQ(database->GetPendingReports(&reports),
CrashReportDatabase::kNoError);
bool report_expected = !options_.set_first_chance_handler ||
options_.crash_type == CrashType::kSimulated;
ASSERT_EQ(reports.size(), report_expected ? 1u : 0u);
if (!report_expected) {
return;
}
std::unique_ptr<const CrashReportDatabase::UploadReport> report;
ASSERT_EQ(database->GetReportForUploading(reports[0].uuid, &report),
CrashReportDatabase::kNoError);
ValidateDump(options_, report.get());
}
StartHandlerForSelfTestOptions options_;
};
TEST_P(StartHandlerForSelfTest, StartHandlerInChild) {
#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
defined(UNDEFINED_SANITIZER)
if (Options().crash_type == CrashType::kInfiniteRecursion) {
GTEST_SKIP();
}
#endif // defined(ADDRESS_SANITIZER)
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
// kFakeSegv does raise(SIGSEGV) to simulate a MTE error which is a SEGSEGV
// that doesn't get reraised automatically, but this causes the child process
// to flakily terminate normally on some bots (e.g. android-nougat-x86-rel)
// for some reason so this is skipped.
if (!Options().set_last_chance_handler &&
Options().crash_type == CrashType::kFakeSegv) {
GTEST_SKIP();
}
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
if (Options().crash_type == CrashType::kSegvWithTagBits) {
#if !defined(ARCH_CPU_ARM64)
GTEST_SKIP() << "Testing for tag bits only exists on aarch64.";
#else
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
struct utsname uname_info;
ASSERT_EQ(uname(&uname_info), 0);
ASSERT_NE(uname_info.release, nullptr);
char* release = uname_info.release;
unsigned major = strtoul(release, &release, 10);
ASSERT_EQ(*release++, '.');
unsigned minor = strtoul(release, nullptr, 10);
if (major < 5 || (major == 5 && minor < 11)) {
GTEST_SKIP() << "Linux kernel v" << uname_info.release
<< " does not support SA_EXPOSE_TAGBITS";
}
#endif // !defined(ARCH_CPU_ARM64)
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
}
StartHandlerForSelfInChildTest test(Options());
test.Run();
}
INSTANTIATE_TEST_SUITE_P(
StartHandlerForSelfTestSuite,
StartHandlerForSelfTest,
testing::Combine(testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Bool(),
testing::Values(CrashType::kSimulated,
CrashType::kBuiltinTrap,
Add SA_EXPOSE_TAGBITS to crashpad's signal handler. SA_EXPOSE_TAGBITS is a Linux >= 5.11 feature that allows si_addr to contain the upper tag bits. This is a feature that allows signal handlers to see the full upper address bits on aarch64, which consist of TBI and MTE nibbles. For MTE, preserving these bits is of significant importance, as it allows for precise use-after-free and buffer-overflow diagnosis that's impossible without seeing these bits in the fault address. We unconditionally enable this feature on all kernels, as it's ignored when unsupported (even on older kernels). Tested on: 1. Linux x86 host, which is a no-op. 2. Android device with Linux 4.14, which is a no-op. 3. Android device with Linux 5.15, which passes. For posterity, my config was: | $ gn args out_arm64 | target_os = "android" | android_ndk_root = "~/Android.sdk/ndk/21.4.7075529" | android_api_level = 26 | target_cpu = "arm64" | # NDK builds push libc++_shared.so, which is not present on newer Android | # versions, so I hacked the runner to push the file. Maybe this should be | # upstreamed at some point as well. | $ git diff | diff --git a/build/run_tests.py b/build/run_tests.py | index 8ad19e34..64269c90 100755 | --- a/build/run_tests.py | +++ b/build/run_tests.py | @@ -273,7 +273,8 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | _adb_shell(adb_mkdir_command) | | # Push the test binary and any other build output to the device. | - local_test_build_artifacts = [] | + local_test_build_artifacts = [ | + '~/Android.sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so'] | for artifact in test_build_artifacts: | local_test_build_artifacts.append(os.path.join( | binary_dir, artifact)) | @@ -294,6 +295,7 @@ def _RunOnAndroidTarget(binary_dir, test, android_device, extra_command_line): | # 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} | + env = {'LD_LIBRARY_PATH': device_out_dir} | gtest_color = os.environ.get('GTEST_COLOR') | if gtest_color in ('auto', None): | if (sys.stdout.isatty() and | $ ninja -C out_arm64 && python build/run_tests.py out_arm64/ \ | --gtest_filter=*StartHandlerForSelfTestSuite* Change-Id: I293b36fcd08ffaca593dae8042299a39756defa0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/4024204 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mitch Phillips <mitchp@google.com>
2022-11-14 15:25:09 -08:00
CrashType::kInfiniteRecursion,
CrashType::kSegvWithTagBits,
CrashType::kFakeSegv)));
// Test state for starting the handler for another process.
class StartHandlerForClientTest {
public:
StartHandlerForClientTest() = default;
StartHandlerForClientTest(const StartHandlerForClientTest&) = delete;
StartHandlerForClientTest& operator=(const StartHandlerForClientTest&) =
delete;
~StartHandlerForClientTest() = default;
bool Initialize(bool sanitize) {
sanitize_ = sanitize;
return UnixCredentialSocket::CreateCredentialSocketpair(&client_sock_,
&server_sock_);
}
bool StartHandlerOnDemand() {
char c;
if (!LoggingReadFileExactly(server_sock_.get(), &c, sizeof(c))) {
ADD_FAILURE();
return false;
}
base::FilePath handler_path = TestPaths::Executable().DirName().Append(
FILE_PATH_LITERAL("crashpad_handler"));
CrashpadClient client;
if (!client.StartHandlerForClient(handler_path,
temp_dir_.path(),
base::FilePath(),
"",
std::map<std::string, std::string>(),
std::vector<std::string>(),
server_sock_.get())) {
ADD_FAILURE();
return false;
}
return true;
}
void ExpectReport() {
auto database =
CrashReportDatabase::InitializeWithoutCreating(temp_dir_.path());
ASSERT_TRUE(database);
std::vector<CrashReportDatabase::Report> reports;
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(), sanitize_);
}
private:
// A signal handler that defers handler process startup to another, presumably
// more privileged, process.
class SandboxedHandler {
public:
SandboxedHandler(const SandboxedHandler&) = delete;
SandboxedHandler& operator=(const SandboxedHandler&) = delete;
static SandboxedHandler* Get() {
static SandboxedHandler* instance = new SandboxedHandler();
return instance;
}
bool Initialize(FileHandle client_sock, bool sanitize) {
client_sock_ = client_sock;
sanitize_ = sanitize;
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
}
private:
SandboxedHandler() = default;
~SandboxedHandler() = delete;
static void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
auto state = Get();
char c = 0;
CHECK(LoggingWriteFile(state->client_sock_, &c, sizeof(c)));
ExceptionInformation exception_information;
exception_information.siginfo_address =
FromPointerCast<decltype(exception_information.siginfo_address)>(
siginfo);
exception_information.context_address =
FromPointerCast<decltype(exception_information.context_address)>(
context);
exception_information.thread_id = syscall(SYS_gettid);
ExceptionHandlerProtocol::ClientInformation info;
info.exception_information_address =
FromPointerCast<decltype(info.exception_information_address)>(
&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_, false);
CHECK_EQ(handler_client.RequestCrashDump(info), 0);
Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
}
FileHandle client_sock_;
bool sanitize_;
};
ScopedTempDir temp_dir_;
ScopedFileHandle client_sock_;
ScopedFileHandle server_sock_;
bool sanitize_;
};
// Tests starting the handler for a child process.
class StartHandlerForChildTest : public Multiprocess {
public:
StartHandlerForChildTest() = default;
StartHandlerForChildTest(const StartHandlerForChildTest&) = delete;
StartHandlerForChildTest& operator=(const StartHandlerForChildTest&) = delete;
~StartHandlerForChildTest() = default;
bool Initialize(bool sanitize) {
SetExpectedChildTerminationBuiltinTrap();
return test_state_.Initialize(sanitize);
}
private:
void MultiprocessParent() {
ASSERT_TRUE(test_state_.StartHandlerOnDemand());
// Wait for chlid to finish.
CheckedReadFileAtEOF(ReadPipeHandle());
test_state_.ExpectReport();
}
[[noreturn]] void MultiprocessChild() {
CHECK(test_state_.InstallHandler());
__builtin_trap();
NOTREACHED();
}
StartHandlerForClientTest test_state_;
};
TEST(CrashpadClient, StartHandlerForChild) {
StartHandlerForChildTest test;
ASSERT_TRUE(test.Initialize(/* sanitize= */ false));
test.Run();
}
TEST(CrashpadClient, SanitizedChild) {
StartHandlerForChildTest test;
ASSERT_TRUE(test.Initialize(/* sanitize= */ true));
test.Run();
}
} // namespace
} // namespace test
} // namespace crashpad