[PATCH] elf: Add __libc_get_static_tls_bounds [BZ #16291]
Fangrui Song
maskray@google.com
Sat Sep 25 00:42:27 GMT 2021
Sanitizer runtimes need static TLS boundaries for a variety of use cases.
* asan/hwasan/msan/tsan need to unpoison static TLS blocks to prevent false
positives due to reusing the TLS blocks with a previous thread.
* lsan needs TCB for pointers into pthread_setspecific regions.
See https://maskray.me/blog/2021-02-14-all-about-thread-local-storage
for details.
compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp GetTls has
to infer the static TLS bounds from TP, _dl_get_tls_static_info, and
hard-coded TCB sizes. Currently this is somewhat robust for
aarch64/powerpc64/x86-64 but is brittle for many other architectures.
This patch implements __libc_get_static_tls_bounds@@GLIBC_PRIVATE which
is available in Android bionic since API level 31. This API allows the
sanitizer code to be more robust. _dl_get_tls_static_info@@GLIBC_PRIVATE
can probably be removed when Clang/GCC sanitizers drop reliance on it.
I am unclear whether the version should be GLIBC_2.*.
Tested that on x86_64-linux-gnu, __libc_get_static_tls_bounds output
matches sanitizer's GetTls.
---
csu/libc-tls.c | 2 ++
elf/Versions | 3 +++
elf/dl-tls.c | 13 +++++++++++++
sysdeps/generic/ldsodefs.h | 6 ++++++
4 files changed, 24 insertions(+)
diff --git a/csu/libc-tls.c b/csu/libc-tls.c
index 5515204863..433c9bfcc6 100644
--- a/csu/libc-tls.c
+++ b/csu/libc-tls.c
@@ -46,6 +46,8 @@ bool _dl_tls_dtv_gaps;
struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list;
/* Number of modules in the static TLS block. */
size_t _dl_tls_static_nelem;
+/* Start of the static TLS block. */
+void *_dl_tls_static_start;
/* Size of the static TLS block. */
size_t _dl_tls_static_size;
/* Size actually allocated in the static TLS block. */
diff --git a/elf/Versions b/elf/Versions
index 775aab62af..ec095022f9 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -72,5 +72,8 @@ ld {
# Set value of a tunable.
__tunable_get_val;
+
+ # Used by sanitizers.
+ __libc_get_static_tls_bounds;
}
}
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index d554ae4497..49edb0e452 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -400,6 +400,15 @@ _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
*alignp = GLRO (dl_tls_static_align);
}
+/* Get start and stop addresses of the static TLS block. This
+ function will be used by Clang and GCC sanitizers. */
+void
+__libc_get_static_tls_bounds (void **startp, void **endp)
+{
+ *startp = GLRO (dl_tls_static_start);
+ *endp = GLRO (dl_tls_static_start) + GLRO (dl_tls_static_size);
+}
+
/* Derive the location of the pointer to the start of the original
allocation (before alignment) from the pointer to the TCB. */
static inline void **
@@ -448,6 +457,8 @@ _dl_allocate_tls_storage (void)
/* Clear the TCB data structure. We can't ask the caller (i.e.
libpthread) to do it, because we will initialize the DTV et al. */
memset (result, '\0', TLS_TCB_SIZE);
+
+ GLRO (dl_tls_static_start) = aligned;
#elif TLS_DTV_AT_TP
/* Pre-TCB and TCB come before the TLS blocks. The layout computed
in _dl_determine_tlsoffset assumes that the TCB is aligned to the
@@ -462,6 +473,8 @@ _dl_allocate_tls_storage (void)
it. We can't ask the caller (i.e. libpthread) to do it, because
we will initialize the DTV et al. */
memset (result - TLS_PRE_TCB_SIZE, '\0', TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
+
+ GLRO (dl_tls_static_start) = result - TLS_PRE_TCB_SIZE;
#endif
/* Record the value of the original pointer for later
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index d49529da0d..ad4672da26 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -609,6 +609,9 @@ struct rtld_global_ro
binaries, don't honor for PIEs). */
EXTERN ElfW(Addr) _dl_use_load_bias;
+ /* Start of the static TLS block. */
+ EXTERN void *_dl_tls_static_start;
+
/* Size of the static TLS block. */
EXTERN size_t _dl_tls_static_size;
@@ -1229,6 +1232,9 @@ rtld_hidden_proto (_dl_allocate_tls)
/* Get size and alignment requirements of the static TLS block. */
extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp);
+/* Get start and end addresses of the static TLS block. */
+extern void __libc_get_static_tls_bounds (void **startp, void **endp);
+
extern void _dl_allocate_static_tls (struct link_map *map) attribute_hidden;
/* These are internal entry points to the two halves of _dl_allocate_tls,
--
2.33.0.685.g46640cef36-goog
More information about the Libc-alpha
mailing list