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>
This commit is contained in:
Mitch Phillips 2022-11-14 15:25:09 -08:00 committed by Crashpad LUCI CQ
parent 72e51701c7
commit fca8871ca3
3 changed files with 57 additions and 6 deletions

View File

@ -180,8 +180,10 @@ class SignalHandler {
DCHECK(!handler_);
handler_ = this;
return Signals::InstallCrashHandlers(
HandleOrReraiseSignal, SA_ONSTACK, &old_actions_, unhandled_signals);
return Signals::InstallCrashHandlers(HandleOrReraiseSignal,
SA_ONSTACK | SA_EXPOSE_TAGBITS,
&old_actions_,
unhandled_signals);
}
const ExceptionInformation& GetExceptionInfo() {

View File

@ -20,6 +20,7 @@
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "base/check_op.h"
@ -69,6 +70,7 @@ enum class CrashType : uint32_t {
kSimulated,
kBuiltinTrap,
kInfiniteRecursion,
kSegvWithTagBits,
};
struct StartHandlerForSelfTestOptions {
@ -170,6 +172,10 @@ void ValidateExtraMemory(const StartHandlerForSelfTestOptions& options,
}
}
EXPECT_EQ(pc_found, options.gather_indirectly_referenced_memory);
if (options.crash_type == CrashType::kSegvWithTagBits) {
EXPECT_EQ(exception->ExceptionAddress(), 0xefull << 56);
}
}
void ValidateDump(const StartHandlerForSelfTestOptions& options,
@ -242,16 +248,28 @@ void DoCrash(const StartHandlerForSelfTestOptions& options,
}
switch (options.crash_type) {
case CrashType::kSimulated:
case CrashType::kSimulated: {
CRASHPAD_SIMULATE_CRASH();
break;
}
case CrashType::kBuiltinTrap:
case CrashType::kBuiltinTrap: {
__builtin_trap();
}
case CrashType::kInfiniteRecursion:
case CrashType::kInfiniteRecursion: {
int val = 42;
exit(RecurseInfinitely(&val));
}
case CrashType::kSegvWithTagBits: {
volatile char* x = nullptr;
#ifdef __aarch64__
x += 0xefull << 56;
#endif // __aarch64__
*x;
break;
}
}
}
@ -416,6 +434,9 @@ class StartHandlerForSelfInChildTest : public MultiprocessExec {
SetExpectedChildTermination(TerminationReason::kTerminationSignal,
SIGSEGV);
break;
case CrashType::kSegvWithTagBits:
SetExpectedChildTermination(TerminationReason::kTerminationSignal,
SIGSEGV);
}
}
}
@ -492,6 +513,27 @@ TEST_P(StartHandlerForSelfTest, StartHandlerInChild) {
GTEST_SKIP();
}
#endif // defined(ADDRESS_SANITIZER)
if (Options().crash_type == CrashType::kSegvWithTagBits) {
#if !defined(ARCH_CPU_ARM64)
GTEST_SKIP() << "Testing for tag bits only exists on aarch64.";
#endif // !defined(ARCH_CPU_ARM64)
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";
}
}
StartHandlerForSelfInChildTest test(Options());
test.Run();
}
@ -506,7 +548,8 @@ INSTANTIATE_TEST_SUITE_P(
testing::Bool(),
testing::Values(CrashType::kSimulated,
CrashType::kBuiltinTrap,
CrashType::kInfiniteRecursion)));
CrashType::kInfiniteRecursion,
CrashType::kSegvWithTagBits)));
// Test state for starting the handler for another process.
class StartHandlerForClientTest {

View File

@ -22,6 +22,12 @@
#define SS_AUTODISARM (1u << 31)
#endif
// Linux Kernel >= 5.11 flag for `sigaction::sa_flags`. Missing in headers from
// earlier versions of Linux.
#if !defined(SA_EXPOSE_TAGBITS)
#define SA_EXPOSE_TAGBITS 0x00000800
#endif
// Missing from glibc and bionic-x86_64
#if defined(__x86_64__) || defined(__i386__)