diff options
author | Ryan Prichard <rprichard@google.com> | 2019-01-17 16:37:11 -0800 |
---|---|---|
committer | Ryan Prichard <rprichard@google.com> | 2019-01-17 17:13:53 -0800 |
commit | bf427f42254f0a8d60dad3d1198c2f589d260cc8 (patch) | |
tree | 357db0946598c5dc08388b51b7503dd33edfd2a2 /linker | |
parent | 9a238653c1a32a7bd046aba8411e7400dda8367e (diff) | |
download | android_bionic-bf427f42254f0a8d60dad3d1198c2f589d260cc8.tar.gz android_bionic-bf427f42254f0a8d60dad3d1198c2f589d260cc8.tar.bz2 android_bionic-bf427f42254f0a8d60dad3d1198c2f589d260cc8.zip |
Fix soinfo_tls::module dangling reference
The field was pointing into an element of an std::vector, but the address
of a vector element is invalidated when the vector is resized.
This bug was caught by the new elftls.shared_ie and
elftls_dl.dlopen_shared_var_ie tests.
Bug: http://b/78026329
Test: bionic unit tests
Change-Id: I7232f6d703a9e339fe8966a95b7a68bae2c9c420
Diffstat (limited to 'linker')
-rw-r--r-- | linker/linker.cpp | 5 | ||||
-rw-r--r-- | linker/linker_soinfo.h | 1 | ||||
-rw-r--r-- | linker/linker_tls.cpp | 24 | ||||
-rw-r--r-- | linker/linker_tls.h | 5 |
4 files changed, 24 insertions, 11 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index 6687d235e..412b8eb8e 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2925,8 +2925,9 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r // Unresolved weak relocation. Leave tpoff at 0 to resolve // &weak_tls_symbol to __get_tls(). } else if (soinfo_tls* lsi_tls = lsi->get_tls()) { - if (lsi_tls->module->static_offset != SIZE_MAX) { - tpoff += lsi_tls->module->static_offset - tls_tp_base; + const TlsModule& mod = get_tls_module(lsi_tls->module_id); + if (mod.static_offset != SIZE_MAX) { + tpoff += mod.static_offset - tls_tp_base; } else { DL_ERR("TLS symbol \"%s\" in dlopened \"%s\" referenced from \"%s\" using IE access model", sym_name, lsi->get_realpath(), get_realpath()); diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h index 87e385db3..14571de5b 100644 --- a/linker/linker_soinfo.h +++ b/linker/linker_soinfo.h @@ -110,7 +110,6 @@ static constexpr size_t kUninitializedModuleId = 0; struct soinfo_tls { TlsSegment segment; size_t module_id = kUninitializedModuleId; - TlsModule* module = nullptr; }; #if defined(__work_around_b_24465209__) diff --git a/linker/linker_tls.cpp b/linker/linker_tls.cpp index a50d92671..0d1796b63 100644 --- a/linker/linker_tls.cpp +++ b/linker/linker_tls.cpp @@ -41,6 +41,9 @@ static bool g_static_tls_finished; static std::vector<TlsModule> g_tls_modules; +static inline size_t module_id_to_idx(size_t id) { return id - 1; } +static inline size_t module_idx_to_id(size_t idx) { return idx + 1; } + static size_t get_unused_module_index() { for (size_t i = 0; i < g_tls_modules.size(); ++i) { if (g_tls_modules[i].soinfo_ptr == nullptr) { @@ -59,13 +62,11 @@ static void register_tls_module(soinfo* si, size_t static_offset) { ScopedWriteLock locker(&__libc_shared_globals()->tls_modules.rwlock); size_t module_idx = get_unused_module_index(); - TlsModule* module = &g_tls_modules[module_idx]; soinfo_tls* si_tls = si->get_tls(); - si_tls->module_id = module_idx + 1; - si_tls->module = module; + si_tls->module_id = module_idx_to_id(module_idx); - *module = { + g_tls_modules[module_idx] = { .segment = si_tls->segment, .static_offset = static_offset, .first_generation = ++__libc_shared_globals()->tls_modules.generation, @@ -77,11 +78,18 @@ static void unregister_tls_module(soinfo* si) { ScopedWriteLock locker(&__libc_shared_globals()->tls_modules.rwlock); soinfo_tls* si_tls = si->get_tls(); - CHECK(si_tls->module->static_offset == SIZE_MAX); - CHECK(si_tls->module->soinfo_ptr == si); - *si_tls->module = {}; + TlsModule& mod = g_tls_modules[module_id_to_idx(si_tls->module_id)]; + CHECK(mod.static_offset == SIZE_MAX); + CHECK(mod.soinfo_ptr == si); + mod = {}; si_tls->module_id = kUninitializedModuleId; - si_tls->module = nullptr; +} + +// The reference is valid until a TLS module is registered or unregistered. +const TlsModule& get_tls_module(size_t module_id) { + size_t module_idx = module_id_to_idx(module_id); + CHECK(module_idx < g_tls_modules.size()); + return g_tls_modules[module_idx]; } __BIONIC_WEAK_FOR_NATIVE_BRIDGE diff --git a/linker/linker_tls.h b/linker/linker_tls.h index 4f4833731..fbb1dcf52 100644 --- a/linker/linker_tls.h +++ b/linker/linker_tls.h @@ -28,6 +28,9 @@ #pragma once +#include <stdlib.h> + +struct TlsModule; struct soinfo; void linker_setup_exe_static_tls(const char* progname); @@ -35,3 +38,5 @@ void linker_finalize_static_tls(); void register_soinfo_tls(soinfo* si); void unregister_soinfo_tls(soinfo* si); + +const TlsModule& get_tls_module(size_t module_id); |