|
|
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 |
{
|