From 7f6290ca9ab4b02eab67262a8a103473c9148acc Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Sat, 16 May 2015 00:34:15 +0000 Subject: [PATCH] [sanitizer] Recognize static TLS in __tls_get_addr interceptor. Current code tries to find the dynamic TLS header to the left of the TLS block without checking that it's not a static TLS allocation. llvm-svn: 237495 --- compiler-rt/lib/asan/asan_interceptors.cc | 7 +++++ compiler-rt/lib/msan/msan_interceptors.cc | 8 ++++++ .../sanitizer_common_interceptors.inc | 8 +++++- .../sanitizer_tls_get_addr.cc | 8 +++++- .../sanitizer_common/sanitizer_tls_get_addr.h | 3 ++- compiler-rt/lib/tsan/rtl/tsan_interceptors.cc | 8 ++++++ .../test/asan/TestCases/Linux/static_tls.cc | 27 +++++++++++++++++++ 7 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 compiler-rt/test/asan/TestCases/Linux/static_tls.cc diff --git a/compiler-rt/lib/asan/asan_interceptors.cc b/compiler-rt/lib/asan/asan_interceptors.cc index 1318785bdc66..d8b48d391ab8 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cc +++ b/compiler-rt/lib/asan/asan_interceptors.cc @@ -182,6 +182,13 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) CoverageUpdateMapping() #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping() #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited) +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (AsanThread *t = GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } #include "sanitizer_common/sanitizer_common_interceptors.inc" // Syscall interceptors don't have contexts, we don't support suppressions diff --git a/compiler-rt/lib/msan/msan_interceptors.cc b/compiler-rt/lib/msan/msan_interceptors.cc index a1e81931b226..ffae221cec44 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cc +++ b/compiler-rt/lib/msan/msan_interceptors.cc @@ -1397,6 +1397,14 @@ int OnExit() { if (map) ForEachMappedRegion(map, __msan_unpoison); \ } while (false) +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (MsanThread *t = GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } + #include "sanitizer_common/sanitizer_common_interceptors.inc" #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 6e81a50ec334..4df015408fb0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -114,6 +114,10 @@ #define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {} #endif +#ifndef COMMON_INTERCEPTOR_GET_TLS_RANGE +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) *begin = *end = 0; +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -3996,7 +4000,9 @@ INTERCEPTOR(void *, __tls_get_addr, void *arg) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg); void *res = REAL(__tls_get_addr)(arg); - DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res); + uptr tls_begin, tls_end; + COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end); if (dtv) { // New DTLS block has been allocated. COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc index 6142ce517db5..ea037159d00b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -78,7 +78,8 @@ void DTLS_Destroy() { DTLS_Deallocate(dtls.dtv, s); } -DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res) { +DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, + uptr static_tls_begin, uptr static_tls_end) { if (!common_flags()->intercept_tls_get_addr) return 0; TlsGetAddrParam *arg = reinterpret_cast(arg_void); uptr dso_id = arg->dso_id; @@ -95,6 +96,11 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res) { tls_size = dtls.last_memalign_size; VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n", tls_beg, tls_size); + } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) { + // This is the static TLS block which was initialized / unpoisoned at thread + // creation. + VPrintf(2, "__tls_get_addr: static tls: %p\n", tls_beg); + tls_size = 0; } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) { // We may want to check gnu_get_libc_version(). Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h index 0fc9a2257c68..58d47634d382 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_tls_get_addr.h @@ -50,7 +50,8 @@ struct DTLS { // Returns pointer and size of a linker-allocated TLS block. // Each block is returned exactly once. -DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res); +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin, + uptr static_tls_end); void DTLS_on_libc_memalign(void *ptr, uptr size); DTLS *DTLS_Get(); void DTLS_Destroy(); // Make sure to call this before the thread is destroyed. diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc index 36d93e0c4bdc..b47332dc3e93 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc @@ -2285,6 +2285,14 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, msg) +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (TsanThread *t = GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } + #include "sanitizer_common/sanitizer_common_interceptors.inc" #define TSAN_SYSCALL() \ diff --git a/compiler-rt/test/asan/TestCases/Linux/static_tls.cc b/compiler-rt/test/asan/TestCases/Linux/static_tls.cc new file mode 100644 index 000000000000..2b2bc41479c2 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Linux/static_tls.cc @@ -0,0 +1,27 @@ +// REQUIRES: asan-64-bits +// Regression test: __tls_get_addr interceptor must recognize static TLS. +// +// RUN: %clangxx_asan -DSHARED %s -shared -o %t-so.so -fPIC +// RUN: %clangxx_asan %s -ldl -pthread -o %t %t-so.so +// RUN: ASAN_OPTIONS=verbosity=2 %run %t 2>&1 | FileCheck %s + +// CHECK: before +// CHECK: __tls_get_addr: static tls +// CHECK: after + +#ifndef SHARED +#include + +unsigned *f(); +int main(int argc, char *argv[]) { + fprintf(stderr, "before\n"); + f(); + fprintf(stderr, "after\n"); + return 0; +} +#else // SHARED +static __thread unsigned ThreadLocal; +unsigned *f() { + return &ThreadLocal; +} +#endif