public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] elf: Add __libc_get_static_tls_bounds [BZ #16291]
@ 2021-09-25  0:42 Fangrui Song
  2021-09-27 13:02 ` Florian Weimer
  2021-09-27 17:38 ` Joseph Myers
  0 siblings, 2 replies; 12+ messages in thread
From: Fangrui Song @ 2021-09-25  0:42 UTC (permalink / raw)
  To: libc-alpha, Adhemerval Zanella, Florian Weimer

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


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-12-21  6:08 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-25  0:42 [PATCH] elf: Add __libc_get_static_tls_bounds [BZ #16291] Fangrui Song
2021-09-27 13:02 ` Florian Weimer
2021-09-27 17:59   ` Fangrui Song
2021-10-06 20:23     ` Fangrui Song
2021-10-15  0:13       ` Fangrui Song
2021-10-19 19:37         ` Fāng-ruì Sòng
2021-10-28  5:16           ` Fāng-ruì Sòng
2021-11-29 19:30             ` Florian Weimer
2021-12-21  2:55               ` Fāng-ruì Sòng
2021-12-21  6:08                 ` Florian Weimer
2021-09-27 17:38 ` Joseph Myers
2021-09-27 17:47   ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).