diff options
Diffstat (limited to 'system/musl/arm64-tls.patch')
-rw-r--r-- | system/musl/arm64-tls.patch | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/system/musl/arm64-tls.patch b/system/musl/arm64-tls.patch new file mode 100644 index 000000000..4a6d7f7a4 --- /dev/null +++ b/system/musl/arm64-tls.patch @@ -0,0 +1,116 @@ +From 6104dae9088da7ffd9346671be867a43a4b03295 Mon Sep 17 00:00:00 2001 +From: Szabolcs Nagy <nsz@port70.net> +Date: Thu, 16 May 2019 17:15:33 +0000 +Subject: fix static tls offsets of shared libs on TLS_ABOVE_TP targets + +tls_offset should always point to the end of the allocated static tls +area, but this was not handled correctly on "tls variant 1" targets +in the dynamic linker: + +after application tls was allocated, tls_offset was aligned up, +potentially wasting tls space. (alignment may be needed at the +begining of the tls area, not at the end, but that will be fixed +separately as it is unlikely to affect real binaries.) + +when static tls was allocated for a shared library, tls_offset was +only updated with the size of the tls segment which does not include +alignment gaps, which can easily happen if the tls size update for +one library leaves tls_offset misaligned for the next one. this can +cause oob access in __copy_tls or arbitrary breakage at tls access. +(the issue was observed on aarch64 with rust binaries) +--- + ldso/dynlink.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/ldso/dynlink.c b/ldso/dynlink.c +index ad0cdba2..967f1fd9 100644 +--- a/ldso/dynlink.c ++++ b/ldso/dynlink.c +@@ -1127,7 +1127,7 @@ static struct dso *load_library(const char *name, struct dso *needed_by) + #ifdef TLS_ABOVE_TP + p->tls.offset = tls_offset + ( (tls_align-1) & + -(tls_offset + (uintptr_t)p->tls.image) ); +- tls_offset += p->tls.size; ++ tls_offset = p->tls.offset + p->tls.size; + #else + tls_offset += p->tls.size + p->tls.align - 1; + tls_offset -= (tls_offset + (uintptr_t)p->tls.image) +@@ -1797,9 +1797,7 @@ _Noreturn void __dls3(size_t *sp) + #ifdef TLS_ABOVE_TP + app.tls.offset = GAP_ABOVE_TP; + app.tls.offset += -GAP_ABOVE_TP & (app.tls.align-1); +- tls_offset = app.tls.offset + app.tls.size +- + ( -((uintptr_t)app.tls.image + app.tls.size) +- & (app.tls.align-1) ); ++ tls_offset = app.tls.offset + app.tls.size; + #else + tls_offset = app.tls.offset = app.tls.size + + ( -((uintptr_t)app.tls.image + app.tls.size) +-- +cgit v1.2.1 + +From a60b9e06861e56c0810bae0249b421e1758d281a Mon Sep 17 00:00:00 2001 +From: Szabolcs Nagy <nsz@port70.net> +Date: Mon, 13 May 2019 18:47:11 +0000 +Subject: fix tls offsets when p_vaddr%p_align != 0 on TLS_ABOVE_TP targets + +currently the bfd linker does not seem to create tls segments where +p_vaddr%p_align != 0, but this is valid in ELF and then the runtime +computed tls offset must satisfy + + offset%p_align == (base+p_vaddr)%p_align + +and in case of local exec tls (main executable) the smallest such +offset must be used (otherwise it is incompatible with the offset +computed by the static linker). the !TLS_ABOVE_TP case is handled +correctly (the offset is negative then in the formula). + +the ldso code for TLS_ABOVE_TP is changed so the static tls offset +of each module satisfies the formula. +--- + ldso/dynlink.c | 7 ++++--- + src/env/__init_tls.c | 3 ++- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/ldso/dynlink.c b/ldso/dynlink.c +index 967f1fd9..1398ff45 100644 +--- a/ldso/dynlink.c ++++ b/ldso/dynlink.c +@@ -1125,8 +1125,8 @@ static struct dso *load_library(const char *name, struct dso *needed_by) + p->tls_id = ++tls_cnt; + tls_align = MAXP2(tls_align, p->tls.align); + #ifdef TLS_ABOVE_TP +- p->tls.offset = tls_offset + ( (tls_align-1) & +- -(tls_offset + (uintptr_t)p->tls.image) ); ++ p->tls.offset = tls_offset + ( (p->tls.align-1) & ++ (-tls_offset + (uintptr_t)p->tls.image) ); + tls_offset = p->tls.offset + p->tls.size; + #else + tls_offset += p->tls.size + p->tls.align - 1; +@@ -1796,7 +1796,8 @@ _Noreturn void __dls3(size_t *sp) + app.tls_id = tls_cnt = 1; + #ifdef TLS_ABOVE_TP + app.tls.offset = GAP_ABOVE_TP; +- app.tls.offset += -GAP_ABOVE_TP & (app.tls.align-1); ++ app.tls.offset += (-GAP_ABOVE_TP + (uintptr_t)app.tls.image) ++ & (app.tls.align-1); + tls_offset = app.tls.offset + app.tls.size; + #else + tls_offset = app.tls.offset = app.tls.size +diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c +index 5f12500c..772baba3 100644 +--- a/src/env/__init_tls.c ++++ b/src/env/__init_tls.c +@@ -115,7 +115,8 @@ static void static_init_tls(size_t *aux) + & (main_tls.align-1); + #ifdef TLS_ABOVE_TP + main_tls.offset = GAP_ABOVE_TP; +- main_tls.offset += -GAP_ABOVE_TP & (main_tls.align-1); ++ main_tls.offset += (-GAP_ABOVE_TP + (uintptr_t)main_tls.image) ++ & (main_tls.align-1); + #else + main_tls.offset = main_tls.size; + #endif +-- +cgit v1.2.1 + |