Andrew Geissler | 82c905d | 2020-04-13 13:39:40 -0500 | [diff] [blame] | 1 | From 8ca8e5cd78cbd37a713e1181f8f6641b57352aa8 Mon Sep 17 00:00:00 2001 |
| 2 | From: Khem Raj <raj.khem@gmail.com> |
| 3 | Date: Wed, 18 Mar 2015 00:20:09 +0000 |
| 4 | Subject: [PATCH] Quote from bug 1443 which explains what the patch does : |
| 5 | |
| 6 | We build some random program and link it with -lust. When we run it, |
| 7 | it dies with a SIGSEGV before reaching main(). |
| 8 | |
| 9 | Libust.so depends on liburcu-bp.so from the usermode-rcu package. |
| 10 | Although libust.so is not prelinked, liburcu-bp.so IS prelinked; this |
| 11 | is critical. |
| 12 | |
| 13 | Libust.so uses a TLS / __thread variable that is defined in liburcu- |
| 14 | bp.so. There are special ARM-specific relocation types that allow two |
| 15 | shared libraries to share thread-specific data. This is critical too. |
| 16 | |
| 17 | One more critical issue: although liburcu-bp.so is prelinked, we can't |
| 18 | load it at its prelinked address, because we also link against |
| 19 | librt.so, and librt.so uses that address. |
| 20 | |
| 21 | The dynamic linker is forced to relink liburcu-bp.so at a different |
| 22 | address. In the course of relinking, it processes the special ARM |
| 23 | relocation record mentioned above. The prelinker has already filled |
| 24 | in the information, which is a short offset into a table of thread- |
| 25 | specific data that is allocated per-thread for each library that uses |
| 26 | TLS. Because the normal behavior of a relocation is to add the symbol |
| 27 | value to an addend stored at the address being relocated, we end up |
| 28 | adding the short offset to itself, doubling it. |
| 29 | |
| 30 | Now we have an awkward situation. The libust.so library doesn't know |
| 31 | about the addend, so its TLS data for this element is correct. The |
| 32 | liburcu-bp.so library has a different offset for the element. When we |
| 33 | go to initialize the element for the first time in liburcu-bp.so, we |
| 34 | write the address of the result at the doubled (broken) offset. |
| 35 | Later, when we refer to the address from libust.so, we check the value |
| 36 | at the correct offset, but it's NULL, so we eat hot SIGSEGV. |
| 37 | |
| 38 | Upstream-Status: Pending |
| 39 | |
| 40 | Signed-off-by: Andrei Dinu <andrei.adrianx.dinu@intel.com> |
| 41 | Signed-off-by: Khem Raj <raj.khem@gmail.com> |
| 42 | --- |
| 43 | sysdeps/arm/dl-machine.h | 2 +- |
| 44 | 1 file changed, 1 insertion(+), 1 deletion(-) |
| 45 | |
| 46 | diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h |
| 47 | index 90856779b1..a29bb86c56 100644 |
| 48 | --- a/sysdeps/arm/dl-machine.h |
| 49 | +++ b/sysdeps/arm/dl-machine.h |
| 50 | @@ -510,7 +510,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, |
| 51 | |
| 52 | case R_ARM_TLS_DTPOFF32: |
| 53 | if (sym != NULL) |
| 54 | - *reloc_addr += sym->st_value; |
| 55 | + *reloc_addr = sym->st_value; |
| 56 | break; |
| 57 | |
| 58 | case R_ARM_TLS_TPOFF32: |