6c0556
commit ddcacd91cc10ff92d6201eda87047d029c14158d
6c0556
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
6c0556
Date:   Thu Feb 11 11:40:11 2021 +0000
6c0556
6c0556
    i386: Avoid lazy relocation of tlsdesc [BZ #27137]
6c0556
    
6c0556
    Lazy tlsdesc relocation is racy because the static tls optimization and
6c0556
    tlsdesc management operations are done without holding the dlopen lock.
6c0556
    
6c0556
    This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67
6c0556
    for aarch64, but it fixes a different race: bug 27137.
6c0556
    
6c0556
    On i386 the code is a bit more complicated than on x86_64 because both
6c0556
    rel and rela relocs are supported.
6c0556
6c0556
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
6c0556
index e5776ef7bc8ad749..3a30671591284d79 100644
6c0556
--- a/sysdeps/i386/dl-machine.h
6c0556
+++ b/sysdeps/i386/dl-machine.h
6c0556
@@ -679,50 +679,32 @@ elf_machine_lazy_rel (struct link_map *map,
6c0556
     }
6c0556
   else if (__glibc_likely (r_type == R_386_TLS_DESC))
6c0556
     {
6c0556
-      struct tlsdesc volatile * __attribute__((__unused__)) td =
6c0556
-	(struct tlsdesc volatile *)reloc_addr;
6c0556
-
6c0556
-      /* Handle relocations that reference the local *ABS* in a simple
6c0556
-	 way, so as to preserve a potential addend.  */
6c0556
-      if (ELF32_R_SYM (reloc->r_info) == 0)
6c0556
-	td->entry = _dl_tlsdesc_resolve_abs_plus_addend;
6c0556
-      /* Given a known-zero addend, we can store a pointer to the
6c0556
-	 reloc in the arg position.  */
6c0556
-      else if (td->arg == 0)
6c0556
-	{
6c0556
-	  td->arg = (void*)reloc;
6c0556
-	  td->entry = _dl_tlsdesc_resolve_rel;
6c0556
-	}
6c0556
-      else
6c0556
-	{
6c0556
-	  /* We could handle non-*ABS* relocations with non-zero addends
6c0556
-	     by allocating dynamically an arg to hold a pointer to the
6c0556
-	     reloc, but that sounds pointless.  */
6c0556
-	  const Elf32_Rel *const r = reloc;
6c0556
-	  /* The code below was borrowed from elf_dynamic_do_rel().  */
6c0556
-	  const ElfW(Sym) *const symtab =
6c0556
-	    (const void *) D_PTR (map, l_info[DT_SYMTAB]);
6c0556
+      const Elf32_Rel *const r = reloc;
6c0556
+      /* The code below was borrowed from elf_dynamic_do_rel().  */
6c0556
+      const ElfW(Sym) *const symtab =
6c0556
+	(const void *) D_PTR (map, l_info[DT_SYMTAB]);
6c0556
 
6c0556
+      /* Always initialize TLS descriptors completely at load time, in
6c0556
+	 case static TLS is allocated for it that requires locking.  */
6c0556
 # ifdef RTLD_BOOTSTRAP
6c0556
-	  /* The dynamic linker always uses versioning.  */
6c0556
-	  assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
6c0556
+      /* The dynamic linker always uses versioning.  */
6c0556
+      assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
6c0556
 # else
6c0556
-	  if (map->l_info[VERSYMIDX (DT_VERSYM)])
6c0556
+      if (map->l_info[VERSYMIDX (DT_VERSYM)])
6c0556
 # endif
6c0556
-	    {
6c0556
-	      const ElfW(Half) *const version =
6c0556
-		(const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
6c0556
-	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
6c0556
-	      elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
6c0556
-			       &map->l_versions[ndx],
6c0556
-			       (void *) (l_addr + r->r_offset), skip_ifunc);
6c0556
-	    }
6c0556
+	{
6c0556
+	  const ElfW(Half) *const version =
6c0556
+	    (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
6c0556
+	  ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
6c0556
+	  elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
6c0556
+			   &map->l_versions[ndx],
6c0556
+			   (void *) (l_addr + r->r_offset), skip_ifunc);
6c0556
+	}
6c0556
 # ifndef RTLD_BOOTSTRAP
6c0556
-	  else
6c0556
-	    elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
6c0556
-			     (void *) (l_addr + r->r_offset), skip_ifunc);
6c0556
+      else
6c0556
+	elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
6c0556
+			 (void *) (l_addr + r->r_offset), skip_ifunc);
6c0556
 # endif
6c0556
-	}
6c0556
     }
6c0556
   else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
6c0556
     {
6c0556
@@ -749,11 +731,21 @@ elf_machine_lazy_rela (struct link_map *map,
6c0556
     ;
6c0556
   else if (__glibc_likely (r_type == R_386_TLS_DESC))
6c0556
     {
6c0556
-      struct tlsdesc volatile * __attribute__((__unused__)) td =
6c0556
-	(struct tlsdesc volatile *)reloc_addr;
6c0556
+      const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
6c0556
+      const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
6c0556
+      const ElfW (Sym) *sym = &symtab[symndx];
6c0556
+      const struct r_found_version *version = NULL;
6c0556
+
6c0556
+      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
6c0556
+	{
6c0556
+	  const ElfW (Half) *vernum =
6c0556
+	    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
6c0556
+	  version = &map->l_versions[vernum[symndx] & 0x7fff];
6c0556
+	}
6c0556
 
6c0556
-      td->arg = (void*)reloc;
6c0556
-      td->entry = _dl_tlsdesc_resolve_rela;
6c0556
+      /* Always initialize TLS descriptors completely at load time, in
6c0556
+	 case static TLS is allocated for it that requires locking.  */
6c0556
+      elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
6c0556
     }
6c0556
   else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
6c0556
     {