• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <dlfcn.h>
30 #include <gtest/gtest.h>
31 
32 #include <thread>
33 
34 #include "gtest_globals.h"
35 #include "private/__get_tls.h"
36 #include "utils.h"
37 
38 #if defined(__BIONIC__)
39 #include "bionic/pthread_internal.h"
40 #endif
41 
42 // Access libtest_elftls_shared_var.so's TLS variable using an IE access.
43 __attribute__((tls_model("initial-exec"))) extern "C" __thread int elftls_shared_var;
44 
TEST(elftls_dl,dlopen_shared_var_ie)45 TEST(elftls_dl, dlopen_shared_var_ie) {
46   // libtest_elftls_shared_var_ie.so can be dlopen'ed, even though it contains a
47   // TLS IE access, because its IE access references a TLS variable from
48   // libtest_elftls_shared_var.so, which is DT_NEEDED by the executable. This
49   // pattern appears in sanitizers, which use TLS IE instrumentation in shared
50   // objects to access special variables exported from the executable or from a
51   // preloaded solib.
52   void* lib = dlopen("libtest_elftls_shared_var_ie.so", RTLD_LOCAL | RTLD_NOW);
53   ASSERT_NE(nullptr, lib);
54 
55   auto bump_shared_var = reinterpret_cast<int(*)()>(dlsym(lib, "bump_shared_var"));
56   ASSERT_NE(nullptr, bump_shared_var);
57 
58   ASSERT_EQ(21, ++elftls_shared_var);
59   ASSERT_EQ(22, bump_shared_var());
60 
61   std::thread([bump_shared_var] {
62     ASSERT_EQ(21, ++elftls_shared_var);
63     ASSERT_EQ(22, bump_shared_var());
64   }).join();
65 }
66 
TEST(elftls_dl,dlopen_ie_error)67 TEST(elftls_dl, dlopen_ie_error) {
68   std::string helper = GetTestlibRoot() +
69       "/elftls_dlopen_ie_error_helper/elftls_dlopen_ie_error_helper";
70   std::string src_path = GetTestlibRoot() + "/libtest_elftls_shared_var_ie.so";
71   std::string dst_path = GetTestlibRoot() + "/libtest_elftls_shared_var.so";
72 #if defined(__BIONIC__)
73   std::string error =
74       "dlerror: dlopen failed: TLS symbol \"elftls_shared_var\" in dlopened \"" + dst_path + "\" " +
75       "referenced from \"" + src_path + "\" using IE access model\n";
76 #else
77   // glibc will reserve some surplus static TLS memory, allowing this test to pass.
78   std::string error = "success\n";
79 #endif
80 
81   chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
82   ExecTestHelper eth;
83   eth.SetArgs({ helper.c_str(), nullptr });
84   eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, error.c_str());
85 }
86 
87 // Use a GD access (__tls_get_addr or TLSDESC) to modify a variable in static
88 // TLS memory.
TEST(elftls_dl,access_static_tls)89 TEST(elftls_dl, access_static_tls) {
90   void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
91   ASSERT_NE(nullptr, lib);
92 
93   auto bump_shared_var = reinterpret_cast<int(*)()>(dlsym(lib, "bump_shared_var"));
94   ASSERT_NE(nullptr, bump_shared_var);
95 
96   ASSERT_EQ(21, ++elftls_shared_var);
97   ASSERT_EQ(22, bump_shared_var());
98 
99   std::thread([bump_shared_var] {
100     ASSERT_EQ(21, ++elftls_shared_var);
101     ASSERT_EQ(22, bump_shared_var());
102   }).join();
103 }
104 
TEST(elftls_dl,bump_local_vars)105 TEST(elftls_dl, bump_local_vars) {
106   void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
107   ASSERT_NE(nullptr, lib);
108 
109   auto bump_local_vars = reinterpret_cast<int(*)()>(dlsym(lib, "bump_local_vars"));
110   ASSERT_NE(nullptr, bump_local_vars);
111 
112   ASSERT_EQ(42, bump_local_vars());
113   std::thread([bump_local_vars] {
114     ASSERT_EQ(42, bump_local_vars());
115   }).join();
116 }
117 
118 extern "C" int* missing_weak_tls_addr();
119 
120 // The Bionic linker resolves a TPREL relocation to an unresolved weak TLS
121 // symbol to 0, which is added to the thread pointer. N.B.: A TPREL relocation
122 // in a static executable is resolved by the static linker instead, and static
123 // linker behavior varies (especially with bfd and gold). See
124 // https://bugs.llvm.org/show_bug.cgi?id=40570.
TEST(elftls_dl,tprel_missing_weak)125 TEST(elftls_dl, tprel_missing_weak) {
126   ASSERT_EQ(static_cast<void*>(__get_tls()), missing_weak_tls_addr());
127   std::thread([] {
128     ASSERT_EQ(static_cast<void*>(__get_tls()), missing_weak_tls_addr());
129   }).join();
130 }
131 
132 // The behavior of accessing an unresolved weak TLS symbol using a dynamic TLS
133 // relocation depends on which kind of implementation the target uses. With
134 // TLSDESC, the result is NULL. With __tls_get_addr, the result is the
135 // generation count (or maybe undefined behavior)? This test only tests TLSDESC.
TEST(elftls_dl,tlsdesc_missing_weak)136 TEST(elftls_dl, tlsdesc_missing_weak) {
137 #if defined(__aarch64__)
138   void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
139   ASSERT_NE(nullptr, lib);
140 
141   auto missing_weak_dyn_tls_addr = reinterpret_cast<int*(*)()>(dlsym(lib, "missing_weak_dyn_tls_addr"));
142   ASSERT_NE(nullptr, missing_weak_dyn_tls_addr);
143 
144   ASSERT_EQ(nullptr, missing_weak_dyn_tls_addr());
145   std::thread([missing_weak_dyn_tls_addr] {
146     ASSERT_EQ(nullptr, missing_weak_dyn_tls_addr());
147   }).join();
148 #else
149   GTEST_SKIP() << "This test is only run on TLSDESC-based targets";
150 #endif
151 }
152 
TEST(elftls_dl,dtv_resize)153 TEST(elftls_dl, dtv_resize) {
154 #if defined(__BIONIC__)
155 #define LOAD_LIB(soname) ({                           \
156     auto lib = dlopen(soname, RTLD_LOCAL | RTLD_NOW); \
157     ASSERT_NE(nullptr, lib);                          \
158     reinterpret_cast<int(*)()>(dlsym(lib, "bump"));   \
159   })
160 
161   auto dtv = []() -> TlsDtv* { return __get_tcb_dtv(__get_bionic_tcb()); };
162 
163   static_assert(sizeof(TlsDtv) == 3 * sizeof(void*),
164                 "This test assumes that the Dtv has a 3-word header");
165 
166   // Initially there are 3 modules:
167   //  - the main test executable
168   //  - libtest_elftls_shared_var
169   //  - libtest_elftls_tprel
170 
171   // The initial DTV is an empty DTV with no generation and a size of 0.
172   TlsDtv* zero_dtv = dtv();
173   ASSERT_EQ(0u, zero_dtv->count);
174   ASSERT_EQ(nullptr, zero_dtv->next);
175   ASSERT_EQ(kTlsGenerationNone, zero_dtv->generation);
176 
177   // Load the fourth module.
178   auto func1 = LOAD_LIB("libtest_elftls_dynamic_filler_1.so");
179   ASSERT_EQ(101, func1());
180 
181   // After loading one module, the DTV should be initialized to the next
182   // power-of-2 size (including the header).
183   TlsDtv* initial_dtv = dtv();
184   ASSERT_EQ(5u, initial_dtv->count);
185   ASSERT_EQ(zero_dtv, initial_dtv->next);
186   ASSERT_LT(0u, initial_dtv->generation);
187 
188   // Load module 5.
189   auto func2 = LOAD_LIB("libtest_elftls_dynamic_filler_2.so");
190   ASSERT_EQ(102, func1());
191   ASSERT_EQ(201, func2());
192   ASSERT_EQ(initial_dtv, dtv());
193   ASSERT_EQ(5u, initial_dtv->count);
194 
195   // Load module 6.
196   auto func3 = LOAD_LIB("libtest_elftls_dynamic_filler_3.so");
197   ASSERT_EQ(103, func1());
198   ASSERT_EQ(202, func2());
199 
200 #if defined(__aarch64__)
201   // The arm64 TLSDESC resolver doesn't update the DTV if it is new enough for
202   // the given access.
203   ASSERT_EQ(5u, dtv()->count);
204 #else
205   // __tls_get_addr updates the DTV anytime the generation counter changes.
206   ASSERT_EQ(13u, dtv()->count);
207 #endif
208 
209   ASSERT_EQ(301, func3());
210 
211   TlsDtv* new_dtv = dtv();
212   ASSERT_EQ(13u, new_dtv->count);
213   ASSERT_NE(initial_dtv, new_dtv);
214   ASSERT_EQ(initial_dtv, new_dtv->next);
215 
216 #undef LOAD_LIB
217 #else
218   GTEST_SKIP() << "test doesn't apply to glibc";
219 #endif
220 }
221 
222 // Verify that variables are reset to their initial values after the library
223 // containing them is closed.
TEST(elftls_dl,dlclose_resets_values)224 TEST(elftls_dl, dlclose_resets_values) {
225   for (int round = 0; round < 2; ++round) {
226     void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
227     ASSERT_NE(nullptr, lib);
228 
229     auto bump_local_vars = reinterpret_cast<int(*)()>(dlsym(lib, "bump_local_vars"));
230     ASSERT_NE(nullptr, bump_local_vars);
231 
232     ASSERT_EQ(42, bump_local_vars());
233     ASSERT_EQ(44, bump_local_vars());
234 
235     ASSERT_EQ(0, dlclose(lib));
236   }
237 }
238 
239 // Calling dlclose should remove the entry for the solib from the global list of
240 // ELF TLS modules. Test that repeatedly loading and unloading a library doesn't
241 // increase the DTV size.
TEST(elftls_dl,dlclose_removes_entry)242 TEST(elftls_dl, dlclose_removes_entry) {
243 #if defined(__BIONIC__)
244   auto dtv = []() -> TlsDtv* { return __get_tcb_dtv(__get_bionic_tcb()); };
245 
246   bool first = true;
247   size_t count = 0;
248 
249   // Use a large number of rounds in case the DTV is initially larger than
250   // expected.
251   for (int round = 0; round < 32; ++round) {
252     void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
253     ASSERT_NE(nullptr, lib);
254 
255     auto bump_local_vars = reinterpret_cast<int(*)()>(dlsym(lib, "bump_local_vars"));
256     ASSERT_NE(nullptr, bump_local_vars);
257 
258     ASSERT_EQ(42, bump_local_vars());
259     if (first) {
260       first = false;
261       count = dtv()->count;
262     } else {
263       ASSERT_EQ(count, dtv()->count);
264     }
265 
266     dlclose(lib);
267   }
268 #else
269   GTEST_SKIP() << "test doesn't apply to glibc";
270 #endif
271 }
272 
273 // Use dlsym to get the address of a TLS variable in static TLS and compare it
274 // against the ordinary address of the variable.
TEST(elftls_dl,dlsym_static_tls)275 TEST(elftls_dl, dlsym_static_tls) {
276   void* lib = dlopen("libtest_elftls_shared_var.so", RTLD_LOCAL | RTLD_NOW);
277   ASSERT_NE(nullptr, lib);
278 
279   int* var_addr = static_cast<int*>(dlsym(lib, "elftls_shared_var"));
280   ASSERT_EQ(&elftls_shared_var, var_addr);
281 
282   std::thread([lib] {
283     int* var_addr = static_cast<int*>(dlsym(lib, "elftls_shared_var"));
284     ASSERT_EQ(&elftls_shared_var, var_addr);
285   }).join();
286 }
287 
288 // Use dlsym to get the address of a TLS variable in dynamic TLS and compare it
289 // against the ordinary address of the variable.
TEST(elftls_dl,dlsym_dynamic_tls)290 TEST(elftls_dl, dlsym_dynamic_tls) {
291   void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
292   ASSERT_NE(nullptr, lib);
293   auto get_var_addr = reinterpret_cast<int*(*)()>(dlsym(lib, "get_large_tls_var_addr"));
294   ASSERT_NE(nullptr, get_var_addr);
295 
296   int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
297   ASSERT_EQ(get_var_addr(), var_addr);
298 
299   std::thread([lib, get_var_addr] {
300     int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
301     ASSERT_EQ(get_var_addr(), var_addr);
302   }).join();
303 }
304 
305 // Calling dladdr on a TLS variable's address doesn't find anything.
TEST(elftls_dl,dladdr_on_tls_var)306 TEST(elftls_dl, dladdr_on_tls_var) {
307   Dl_info info;
308 
309   // Static TLS variable
310   ASSERT_EQ(0, dladdr(&elftls_shared_var, &info));
311 
312   // Dynamic TLS variable
313   void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
314   ASSERT_NE(nullptr, lib);
315   int* var_addr = static_cast<int*>(dlsym(lib, "large_tls_var"));
316   ASSERT_EQ(0, dladdr(var_addr, &info));
317 }
318 
319 // Verify that dladdr does not misinterpret a TLS symbol's value as a virtual
320 // address.
TEST(elftls_dl,dladdr_skip_tls_symbol)321 TEST(elftls_dl, dladdr_skip_tls_symbol) {
322   void* lib = dlopen("libtest_elftls_dynamic.so", RTLD_LOCAL | RTLD_NOW);
323 
324   auto get_local_addr = reinterpret_cast<void*(*)()>(dlsym(lib, "get_local_addr"));
325   ASSERT_NE(nullptr, get_local_addr);
326   void* local_addr = get_local_addr();
327 
328   Dl_info info;
329   ASSERT_NE(0, dladdr(local_addr, &info));
330 
331   std::string libpath = GetTestlibRoot() + "/libtest_elftls_dynamic.so";
332   char dli_realpath[PATH_MAX];
333   ASSERT_TRUE(realpath(info.dli_fname, dli_realpath));
334   ASSERT_STREQ(libpath.c_str(), dli_realpath);
335   ASSERT_STREQ(nullptr, info.dli_sname);
336   ASSERT_EQ(nullptr, info.dli_saddr);
337 }
338