diff options
author | R. Christian McDonald <rcm@rcm.sh> | 2023-11-03 12:56:58 +0000 |
---|---|---|
committer | Kristof Provost <kp@FreeBSD.org> | 2023-11-03 21:43:40 +0000 |
commit | 98fd69f0090da73d9d0451bd769d7752468284c6 (patch) | |
tree | 6b2fdb20e3d9d5766cd4ce0e52803a6382660b19 | |
parent | 6c3ae01cc75afdd575f54289b2879a7c98d55bf6 (diff) | |
download | src-98fd69f0090da73d9d0451bd769d7752468284c6.tar.gz src-98fd69f0090da73d9d0451bd769d7752468284c6.zip |
rtld/arm: fix initial-exec (IE) thread-local storage relocation
net/frr[89] revealed an interesting edge-case on arm when dynamically
linking a shared library that declares more than one static TLS variable
with at least one using the "initial-exec" TLS model. In the case
of frr[89], this library was libfrr.so which essentially does the
following:
#include <stdio.h>
#include "lib.h"
static __thread int *a
__attribute__((tls_model("initial-exec")));
void lib_test()
{
static __thread int b = -1;
printf("&a = %p\n", &a);
printf(" a = %p\n", a);
printf("\n");
printf("&b = %p\n", &b);
printf(" b = %d\n", b);
}
Allocates a file scoped `static __thread` pointer with
tls_model("initial-exec") and later a block scoped TLS int. Notice in
the above minimal reproducer, `b == -1`. The relocation process does
the wrong thing and ends up pointing both `a` and `b` at the same place
in memory.
The output of the above in the broken state is:
&a = 0x4009c018
a = 0xffffffff
&b = 0x4009c018
b = -1
With the patch applied, the output becomes:
&a = 0x4009c01c
a = 0x0
&b = 0x4009c018
b = -1
Reviewed by: kib
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D42415/
-rw-r--r-- | libexec/rtld-elf/arm/reloc.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c index c3e95940be74..6efc9f499761 100644 --- a/libexec/rtld-elf/arm/reloc.c +++ b/libexec/rtld-elf/arm/reloc.c @@ -280,10 +280,13 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache, return -1; tmp = (Elf_Addr)def->st_value + defobj->tlsoffset; - if (__predict_true(RELOC_ALIGNED_P(where))) + if (__predict_true(RELOC_ALIGNED_P(where))) { + tmp += *where; *where = tmp; - else + } else { + tmp += load_ptr(where); store_ptr(where, tmp); + } dbg("TLS_TPOFF32 %s in %s --> %p", obj->strtab + obj->symtab[symnum].st_name, obj->path, (void *)tmp); |