From aff9c5e87bb17e12142d5eb1a0514662d9433ee6 Mon Sep 17 00:00:00 2001 From: Julian Lettner Date: Tue, 9 Jul 2019 21:27:37 +0000 Subject: Reland "[TSan] Improve handling of stack pointer mangling in {set,long}jmp, pt.8" Fix compilation errors related to `SANITIZER_GO` `#ifdef`s. Refine longjmp key management. For Linux, re-implement key retrieval in C (instead of assembly). Removal of `InitializeGuardPtr` and a final round of cleanups will be done in the next commit. Reviewed By: dvyukov Differential Revision: https://reviews.llvm.org/D64092 llvm-svn: 365513 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@365560 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform_linux.cc | 60 +++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 71f6f4872..b470a46e0 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -68,12 +68,17 @@ void *__libc_stack_end = 0; #endif #if SANITIZER_LINUX && defined(__aarch64__) -void InitializeGuardPtr() __attribute__((visibility("hidden"))); +__tsan::uptr InitializeGuardPtr() __attribute__((visibility("hidden"))); extern "C" __tsan::uptr _tsan_pointer_chk_guard; #endif namespace __tsan { +#if SANITIZER_LINUX && defined(__aarch64__) && !SANITIZER_GO +static void InitializeLongjmpXorKey(); +static uptr longjmp_xor_key; +#endif + #ifdef TSAN_RUNTIME_VMA // Runtime detected VMA size. uptr vmaSize; @@ -249,7 +254,8 @@ void InitializePlatform() { // Go maps shadow memory lazily and works fine with limited address space. // Unlimited stack is not a problem as well, because the executable // is not compiled with -pie. - if (!SANITIZER_GO) { +#if !SANITIZER_GO + { bool reexec = false; // TSan doesn't play well with unlimited stack size (as stack // overlaps with shadow memory). If we detect unlimited stack size, @@ -285,16 +291,33 @@ void InitializePlatform() { reexec = true; } // Initialize the guard pointer used in {sig}{set,long}jump. - InitializeGuardPtr(); + longjmp_xor_key = InitializeGuardPtr(); + uptr old_value = longjmp_xor_key; + InitializeLongjmpXorKey(); + CHECK_EQ(longjmp_xor_key, old_value); + // If the above check fails for you, please contact me (jlettner@apple.com) + // and let me know the values of the two differing keys. Please also set a + // breakpoint on `InitializeGuardPtr` and `InitializeLongjmpXorKey` and tell + // me the stack pointer (SP) values that go into the XOR operation (where we + // derive the key): + // + // InitializeLongjmpXorKey: + // uptr sp = (uptr)__builtin_frame_address(0); + // + // InitializeGuardPtr (in tsan_rtl_aarch64.S): + // mov x0, sp + // ... + // eor x0, x0, x1 + // + // Then feel free to comment out the call to `InitializeLongjmpXorKey`. #endif if (reexec) ReExec(); } -#if !SANITIZER_GO CheckAndProtect(); InitTlsSize(); -#endif +#endif // !SANITIZER_GO } #if !SANITIZER_GO @@ -353,9 +376,7 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { # endif #elif defined(__aarch64__) # if SANITIZER_LINUX - // TODO(yln): fix this - // return mangled_sp ^ _tsan_pointer_chk_guard; - return mangled_sp; + return mangled_sp ^ longjmp_xor_key; # else return mangled_sp; # endif @@ -394,6 +415,27 @@ uptr ExtractLongJmpSp(uptr *env) { return UnmangleLongJmpSp(mangled_sp); } +#if SANITIZER_LINUX && defined(__aarch64__) +#include "interception/interception.h" +DECLARE_REAL(int, setjmp, void* env); +// GLIBC mangles the function pointers in jmp_buf (used in {set,long}*jmp +// functions) by XORing them with a random key. For AArch64 it is a global +// variable rather than a TCB one (as for x86_64/powerpc). We obtain the key by +// issuing a setjmp and XORing the SP pointer values to derive the key. +static void InitializeLongjmpXorKey() { + // 1. Call REAL(setjmp), which stores the mangled SP in env. + jmp_buf env; + REAL(setjmp)(env); + + // 2. Retrieve mangled/vanilla SP. + uptr mangled_sp = ((uptr *)&env)[LONG_JMP_SP_ENV_SLOT]; + uptr sp = (uptr)__builtin_frame_address(0); + + // 3. xor SPs to obtain key. + longjmp_xor_key = mangled_sp ^ sp; +} +#endif + void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) { // Check that the thr object is in tls; const uptr thr_beg = (uptr)thr; @@ -421,7 +463,7 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, pthread_cleanup_pop(0); return res; } -#endif +#endif // !SANITIZER_GO #if !SANITIZER_GO void ReplaceSystemMalloc() { } -- cgit v1.2.1