Guard against linker[64] having a PT_TLS segment
The loader doesn't currently support using TLS within itself.
Previously, if a TLS segment was accidentally linked into the loader,
then the loader's `soinfo_tls* tls_` field would be initialized with a
valid TlsSegment, but the loader soinfo wouldn't be registered with
linker_tls.cpp, so the module ID would be 0. (The first valid module ID
is 1.)
The result was architecture-dependent. On x86, everything worked until
the first TLS access, which segfaulted. On arm64, relocating TLSDESC
hit a CHECK() failure on the invalid module ID.
Make the loader more robust:
* Abort in the loader if it detects that it has a TLS segment.
* For R_GENERIC_TLS_DTPMOD, verify that a module ID is valid before
writing it.
Bug: none
Test: manually add a thread_local variable to the loader
Test: bionic-unit-tests
Change-Id: I93c17ca65df4af2d46288957a0e483b0e2b13862
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b0caedd..bcd73aa 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2866,11 +2866,12 @@
TlsSegment tls_segment;
if (__bionic_get_tls_segment(phdr, phnum, load_bias, &tls_segment)) {
+ // The loader does not (currently) support ELF TLS, so it shouldn't have
+ // a TLS segment.
+ CHECK(!relocating_linker && "TLS not supported in loader");
if (!__bionic_check_tls_alignment(&tls_segment.alignment)) {
- if (!relocating_linker) {
- DL_ERR("TLS segment alignment in \"%s\" is not a power of 2: %zu",
- get_realpath(), tls_segment.alignment);
- }
+ DL_ERR("TLS segment alignment in \"%s\" is not a power of 2: %zu", get_realpath(),
+ tls_segment.alignment);
return false;
}
tls_ = std::make_unique<soinfo_tls>();