Index: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc +++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc @@ -68,12 +68,17 @@ #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__) +static void InitializeLongjmpXorKey(); +static uptr longjmp_xor_key; +#endif + #ifdef TSAN_RUNTIME_VMA // Runtime detected VMA size. uptr vmaSize; @@ -285,7 +290,25 @@ 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(); @@ -353,9 +376,7 @@ # 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,25 @@ return UnmangleLongJmpSp(mangled_sp); } +#if SANITIZER_LINUX && defined(__aarch64__) +// 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. + jump_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; Index: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc +++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc @@ -238,8 +238,7 @@ #endif } -static const uptr kPthreadSetjmpXorKeySlot = 0x7; -extern "C" uptr __tsan_darwin_setjmp_xor_key = 0; +static uptr longjmp_xor_key = 0; void InitializePlatform() { DisableCoreDumperIfNecessary(); @@ -254,8 +253,9 @@ #endif if (GetMacosVersion() >= MACOS_VERSION_MOJAVE) { - __tsan_darwin_setjmp_xor_key = - (uptr)pthread_getspecific(kPthreadSetjmpXorKeySlot); + // Libsystem currently uses a process-global key; this might change. + const unsigned kTLSLongjmpXorKeySlot = 0x7; + longjmp_xor_key = (uptr)pthread_getspecific(kTLSLongjmpXorKeySlot); } } @@ -268,7 +268,8 @@ uptr ExtractLongJmpSp(uptr *env) { uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT]; - return mangled_sp ^ __tsan_darwin_setjmp_xor_key; + uptr sp = mangled_sp ^ longjmp_xor_key; + return sp; } #if !SANITIZER_GO