Bläddra i källkod

ldso: harden _dl_tls_get_addr_soft against an unusable DTV

_dl_tls_get_addr_soft (used to fill dl_phdr_info::dlpi_tls_data) is
reached from dl_iterate_phdr, which the unwinder calls during stack
unwinding - including pthread cancellation.  In such a context the
calling thread may have no usable thread pointer / DTV, so THREAD_DTV()
can return a near-null bogus pointer and the dtv[-1] dereference faults.
This crashed tst-cancel7, where a thread is cancelled inside system().

dlpi_tls_data is optional information for callers such as libsanitizer,
so return NULL when the DTV pointer is obviously invalid instead of
dereferencing it.

Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
ramin 1 vecka sedan
förälder
incheckning
d8ae8c688c
1 ändrade filer med 8 tillägg och 0 borttagningar
  1. 8 0
      ldso/ldso/dl-tls.c

+ 8 - 0
ldso/ldso/dl-tls.c

@@ -900,7 +900,15 @@ _dl_tls_get_addr_soft (struct link_map *map)
   if (map->l_tls_modid == 0)
     return NULL;
 
+  /* This is called from dl_iterate_phdr to fill dl_phdr_info::dlpi_tls_data,
+     which the unwinder invokes during stack unwinding (e.g. pthread
+     cancellation).  In such contexts the calling thread may not have a
+     usable thread pointer / DTV yet (or any more), so THREAD_DTV() can
+     come back as a near-null bogus pointer.  dlpi_tls_data is optional,
+     so bail out instead of dereferencing it.  */
   dtv = THREAD_DTV ();
+  if (dtv == NULL || (uintptr_t) dtv < 4096)
+    return NULL;
   if (map->l_tls_modid > (size_t) dtv[-1].counter)
     return NULL;