From 1b13b14758257350cb76381b52c906685ed58c74 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 8 Aug 2023 16:00:30 -0700 Subject: [PATCH] crasher: add pac and bti crashes. Also add the missing `.size` directives to all the assembler functions for slightly improved backtraces. Test: crasher64 pac; crasher64 bti Change-Id: I8e0c127cbff56c33637e6ca8f1d927b971951807 --- debuggerd/crasher/arm/crashglue.S | 8 ++-- debuggerd/crasher/arm64/crashglue.S | 45 +++++++++++++++++++-- debuggerd/crasher/crasher.cpp | 56 ++++++++++++++++++++++----- debuggerd/crasher/riscv64/crashglue.S | 6 ++- debuggerd/crasher/x86/crashglue.S | 6 ++- debuggerd/crasher/x86_64/crashglue.S | 6 ++- 6 files changed, 105 insertions(+), 22 deletions(-) diff --git a/debuggerd/crasher/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S index e4adf403c..0def8aee3 100644 --- a/debuggerd/crasher/arm/crashglue.S +++ b/debuggerd/crasher/arm/crashglue.S @@ -23,10 +23,11 @@ crash1: ldr lr, [lr] b . .cfi_endproc + .size crash1, .-crash1 -.globl crashnostack -.type crashnostack, %function -crashnostack: +.globl crash_no_stack +.type crash_no_stack, %function +crash_no_stack: .cfi_startproc mov r1, sp .cfi_def_cfa_register r1 @@ -35,3 +36,4 @@ crashnostack: ldr r0, [r0] b . .cfi_endproc + .size crash_no_stack, .-crash_no_stack diff --git a/debuggerd/crasher/arm64/crashglue.S b/debuggerd/crasher/arm64/crashglue.S index 97c824efb..c56e19a38 100644 --- a/debuggerd/crasher/arm64/crashglue.S +++ b/debuggerd/crasher/arm64/crashglue.S @@ -41,11 +41,12 @@ crash1: ldr x30, [x30] b . .cfi_endproc + .size crash1, .-crash1 -.globl crashnostack -.type crashnostack, %function -crashnostack: +.globl crash_no_stack +.type crash_no_stack, %function +crash_no_stack: .cfi_startproc mov x1, sp .cfi_def_cfa_register x1 @@ -54,3 +55,41 @@ crashnostack: ldr x0, [x0] b . .cfi_endproc + .size crash_no_stack, .-crash_no_stack + + +.globl crash_bti +.type crash_bti, %function +crash_bti: + .cfi_startproc + adr x16, 1f + br x16 +1: // Deliberatly not a bti instruction so we crash here. + b . + .cfi_endproc + .size crash_bti, .-crash_bti + + +.globl crash_pac +.type crash_pac, %function +crash_pac: + .cfi_startproc + paciasp + // Since sp is a pac input, this ensures a mismatch. + sub sp, sp, #16 + autiasp + b . + .cfi_endproc + .size crash_pac, .-crash_pac + +// Set the PAC and BTI bits for this object file. +.section .note.gnu.property, "a" +.balign 8 +.long 4 +.long 0x10 +.long 0x5 +.asciz "GNU" +.long 0xc0000000 +.long 4 +.long 0x3 +.long 0 diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index 12ba502ec..3b52776d7 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,9 @@ #include #include +#include +#include + // We test both kinds of logging. #include #include @@ -59,8 +63,10 @@ typedef int (__kuser_cmpxchg64_t)(const int64_t*, const int64_t*, volatile int64 // Avoid name mangling so that stacks are more readable. extern "C" { -void crash1(void); -void crashnostack(void); +void crash1(); +void crash_no_stack(); +void crash_bti(); +void crash_pac(); int do_action(const char* arg); @@ -196,13 +202,6 @@ static int usage() { fprintf(stderr, " fdsan_file close a file descriptor that's owned by a FILE*\n"); fprintf(stderr, " fdsan_dir close a file descriptor that's owned by a DIR*\n"); fprintf(stderr, " seccomp fail a seccomp check\n"); -#if defined(__arm__) - fprintf(stderr, " kuser_helper_version call kuser_helper_version\n"); - fprintf(stderr, " kuser_get_tls call kuser_get_tls\n"); - fprintf(stderr, " kuser_cmpxchg call kuser_cmpxchg\n"); - fprintf(stderr, " kuser_memory_barrier call kuser_memory_barrier\n"); - fprintf(stderr, " kuser_cmpxchg64 call kuser_cmpxchg64\n"); -#endif fprintf(stderr, " xom read execute-only memory\n"); fprintf(stderr, "\n"); fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n"); @@ -223,6 +222,20 @@ static int usage() { fprintf(stderr, "\n"); fprintf(stderr, " no_new_privs set PR_SET_NO_NEW_PRIVS and then abort\n"); fprintf(stderr, "\n"); +#if defined(__arm__) + fprintf(stderr, "Also, since this is an arm32 binary:\n"); + fprintf(stderr, " kuser_helper_version call kuser_helper_version\n"); + fprintf(stderr, " kuser_get_tls call kuser_get_tls\n"); + fprintf(stderr, " kuser_cmpxchg call kuser_cmpxchg\n"); + fprintf(stderr, " kuser_memory_barrier call kuser_memory_barrier\n"); + fprintf(stderr, " kuser_cmpxchg64 call kuser_cmpxchg64\n"); +#endif +#if defined(__aarch64__) + fprintf(stderr, "Also, since this is an arm64 binary:\n"); + fprintf(stderr, " bti fail a branch target identification (BTI) check\n"); + fprintf(stderr, " pac fail a pointer authentication (PAC) check\n"); +#endif + fprintf(stderr, "\n"); fprintf(stderr, "prefix any of the above with 'thread-' to run on a new thread\n"); fprintf(stderr, "prefix any of the above with 'exhaustfd-' to exhaust\n"); fprintf(stderr, "all available file descriptors before crashing.\n"); @@ -231,6 +244,21 @@ static int usage() { return EXIT_FAILURE; } +[[maybe_unused]] static void CheckCpuFeature(const std::string& name) { + std::string cpuinfo; + if (!android::base::ReadFileToString("/proc/cpuinfo", &cpuinfo)) { + error(1, errno, "couldn't read /proc/cpuinfo"); + } + std::vector lines = android::base::Split(cpuinfo, "\n"); + for (std::string_view line : lines) { + if (!android::base::ConsumePrefix(&line, "Features\t:")) continue; + std::vector features = android::base::Split(std::string(line), " "); + if (std::find(features.begin(), features.end(), name) == features.end()) { + error(1, 0, "/proc/cpuinfo does not report feature '%s'", name.c_str()); + } + } +} + noinline int do_action(const char* arg) { // Prefixes. if (!strncmp(arg, "wait-", strlen("wait-"))) { @@ -256,7 +284,7 @@ noinline int do_action(const char* arg) { } else if (!strcasecmp(arg, "stack-overflow")) { overflow_stack(nullptr); } else if (!strcasecmp(arg, "nostack")) { - crashnostack(); + crash_no_stack(); } else if (!strcasecmp(arg, "exit")) { exit(1); } else if (!strcasecmp(arg, "call-null")) { @@ -349,6 +377,14 @@ noinline int do_action(const char* arg) { __kuser_dmb(); } else if (!strcasecmp(arg, "kuser_cmpxchg64")) { return __kuser_cmpxchg64(0, 0, 0); +#endif +#if defined(__aarch64__) + } else if (!strcasecmp(arg, "bti")) { + CheckCpuFeature("bti"); + crash_bti(); + } else if (!strcasecmp(arg, "pac")) { + CheckCpuFeature("paca"); + crash_pac(); #endif } else if (!strcasecmp(arg, "no_new_privs")) { if (prctl(PR_SET_NO_NEW_PRIVS, 1) != 0) { diff --git a/debuggerd/crasher/riscv64/crashglue.S b/debuggerd/crasher/riscv64/crashglue.S index 42f59b345..f179e3368 100644 --- a/debuggerd/crasher/riscv64/crashglue.S +++ b/debuggerd/crasher/riscv64/crashglue.S @@ -43,10 +43,11 @@ crash1: ld t2, 0(zero) j . .cfi_endproc + .size crash1, .-crash1 -.globl crashnostack -crashnostack: +.globl crash_no_stack +crash_no_stack: .cfi_startproc mv t1, sp .cfi_def_cfa_register t1 @@ -54,3 +55,4 @@ crashnostack: ld t2, 0(zero) j . .cfi_endproc + .size crash_no_stack, .-crash_no_stack diff --git a/debuggerd/crasher/x86/crashglue.S b/debuggerd/crasher/x86/crashglue.S index e8eb3a7ca..453035bf8 100644 --- a/debuggerd/crasher/x86/crashglue.S +++ b/debuggerd/crasher/x86/crashglue.S @@ -6,13 +6,15 @@ crash1: movl $0, %edx jmp *%edx + .size crash1, .-crash1 -.globl crashnostack -crashnostack: +.globl crash_no_stack +crash_no_stack: .cfi_startproc movl %esp, %eax .cfi_def_cfa_register %eax movl $0, %esp movl (%esp), %ebx .cfi_endproc + .size crash_no_stack, .-crash_no_stack diff --git a/debuggerd/crasher/x86_64/crashglue.S b/debuggerd/crasher/x86_64/crashglue.S index 8f6721478..c3d39c483 100644 --- a/debuggerd/crasher/x86_64/crashglue.S +++ b/debuggerd/crasher/x86_64/crashglue.S @@ -6,13 +6,15 @@ crash1: movl $0, %edx jmp *%rdx + .size crash1, .-crash1 -.globl crashnostack -crashnostack: +.globl crash_no_stack +crash_no_stack: .cfi_startproc movq %rsp, %rax .cfi_def_cfa_register %rax movq $0, %rsp movq (%rsp), %rbx .cfi_endproc + .size crash_no_stack, .-crash_no_stack