Fix off-by-one OOB read in elf/tst-tls20
[glibc.git] / elf / tst-tls20.c
blob9cebe22a402e9c9d2c85384521c5e5ba52405816
1 /* Test dtv setup if entries don't have monotone increasing generation.
2 Copyright (C) 2021-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <array_length.h>
20 #include <dlfcn.h>
21 #include <pthread.h>
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <support/check.h>
27 #include <support/support.h>
28 #include <support/test-driver.h>
29 #include <support/xdlfcn.h>
30 #include <support/xthread.h>
32 #define NMOD 100
33 static void *mod[NMOD];
35 static void
36 load_fail (void)
38 /* Expected to fail because of a missing symbol. */
39 void *m = dlopen ("tst-tls20mod-bad.so", RTLD_NOW);
40 if (m != NULL)
41 FAIL_EXIT1 ("dlopen of tst-tls20mod-bad.so succeeded\n");
44 static void
45 load_mod (int i)
47 char *buf = xasprintf ("tst-tls-manydynamic%02dmod.so", i);
48 mod[i] = xdlopen (buf, RTLD_LAZY);
49 free (buf);
52 static void
53 unload_mod (int i)
55 if (mod[i] != NULL)
56 xdlclose (mod[i]);
57 mod[i] = NULL;
60 static void
61 access (int i)
63 char *buf = xasprintf ("tls_global_%02d", i);
64 dlerror ();
65 int *p = dlsym (mod[i], buf);
66 if (test_verbose)
67 printf ("mod[%d]: &tls = %p\n", i, p);
68 if (p == NULL)
69 FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
70 TEST_COMPARE (*p, 0);
71 ++*p;
72 free (buf);
75 static void
76 access_mod (const char *modname, void *mod, int i)
78 char *modsym = xasprintf ("tls_global_%d", i);
79 dlerror ();
80 int *p = dlsym (mod, modsym);
81 if (test_verbose)
82 printf ("%s: &tls = %p\n", modname, p);
83 if (p == NULL)
84 FAIL_EXIT1 ("dlsym failed: %s\n", dlerror ());
85 TEST_COMPARE (*p, 0);
86 ++*p;
87 free (modsym);
90 static void
91 access_dep (int i)
93 char *modname = xasprintf ("tst-tls-manydynamic%dmod-dep.so", i);
94 void *moddep = xdlopen (modname, RTLD_LAZY);
95 access_mod (modname, moddep, i);
96 free (modname);
97 xdlclose (moddep);
100 struct start_args
102 const char *modname;
103 void *mod;
104 int modi;
105 int ndeps;
106 const int *deps;
109 static void *
110 start (void *a)
112 struct start_args *args = a;
114 for (int i = 0; i < NMOD; i++)
115 if (mod[i] != NULL)
116 access (i);
118 if (args != NULL)
120 access_mod (args->modname, args->mod, args->modi);
121 for (int n = 0; n < args->ndeps; n++)
122 access_dep (args->deps[n]);
125 return 0;
128 /* This test gaps with shared libraries with dynamic TLS that has no
129 dependencies. The DTV gap is set with by trying to load an invalid
130 module, the entry should be used on the dlopen. */
131 static void
132 do_test_no_depedency (void)
134 for (int i = 0; i < NMOD; i++)
136 load_mod (i);
137 /* Bump the generation of mod[0] without using new dtv slot. */
138 unload_mod (0);
139 load_fail (); /* Ensure GL(dl_tls_dtv_gaps) is true: see bug 27135. */
140 load_mod (0);
141 /* Access TLS in all loaded modules. */
142 pthread_t t = xpthread_create (0, start, 0);
143 xpthread_join (t);
145 for (int i = 0; i < NMOD; i++)
146 unload_mod (i);
149 /* The following test check DTV gaps handling with shared libraries that has
150 dependencies. It defines 5 different sets:
152 1. Single dependency:
153 mod0 -> mod1
154 2. Double dependency:
155 mod2 -> [mod3,mod4]
156 3. Double dependency with each dependency depent of another module:
157 mod5 -> [mod6,mod7] -> mod8
158 4. Long chain with one double dependency in the middle:
159 mod9 -> [mod10, mod11] -> mod12 -> mod13
160 5. Long chain with two double depedencies in the middle:
161 mod14 -> mod15 -> [mod16, mod17]
162 mod15 -> [mod18, mod19]
164 This does not cover all the possible gaps and configuration, but it
165 should check if different dynamic shared sets are placed correctly in
166 different gaps configurations. */
168 static int
169 nmodules (uint32_t v)
171 unsigned int r = 0;
172 while (v >>= 1)
173 r++;
174 return r + 1;
177 static inline bool
178 is_mod_set (uint32_t g, uint32_t n)
180 return (1U << (n - 1)) & g;
183 static void
184 print_gap (uint32_t g)
186 if (!test_verbose)
187 return;
188 printf ("gap: ");
189 int nmods = nmodules (g);
190 for (int n = 1; n <= nmods; n++)
191 printf ("%c", ((1 << (n - 1)) & g) == 0 ? 'G' : 'M');
192 printf ("\n");
195 static void
196 do_test_dependency (void)
198 /* Maps the module and its dependencies, use thread to access the TLS on
199 each loaded module. */
200 static const int tlsmanydeps0[] = { 1 };
201 static const int tlsmanydeps1[] = { 3, 4 };
202 static const int tlsmanydeps2[] = { 6, 7, 8 };
203 static const int tlsmanydeps3[] = { 10, 11, 12 };
204 static const int tlsmanydeps4[] = { 15, 16, 17, 18, 19 };
205 static const struct tlsmanydeps_t
207 int modi;
208 int ndeps;
209 const int *deps;
210 } tlsmanydeps[] =
212 { 0, array_length (tlsmanydeps0), tlsmanydeps0 },
213 { 2, array_length (tlsmanydeps1), tlsmanydeps1 },
214 { 5, array_length (tlsmanydeps2), tlsmanydeps2 },
215 { 9, array_length (tlsmanydeps3), tlsmanydeps3 },
216 { 14, array_length (tlsmanydeps4), tlsmanydeps4 },
219 /* The gap configuration is defined as a bitmap: the bit set represents a
220 loaded module prior the tests execution, while a bit unsed is a module
221 unloaded. Not all permtation will show gaps, but it is simpler than
222 define each one independently. */
223 for (uint32_t g = 0; g < 64; g++)
225 print_gap (g);
226 int nmods = nmodules (g);
228 int mods[nmods];
229 /* We use '0' as indication for a gap, to avoid the dlclose on iteration
230 cleanup. */
231 for (int n = 1; n < nmods; n++)
233 load_mod (n);
234 mods[n] = n;
236 for (int n = 1; n < nmods; n++)
238 if (!is_mod_set (g, n))
240 unload_mod (n);
241 mods[n] = 0;
245 for (int t = 0; t < array_length (tlsmanydeps); t++)
247 char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep.so",
248 tlsmanydeps[t].modi);
249 void *moddep = xdlopen (moddepname, RTLD_LAZY);
251 /* Access TLS in all loaded modules. */
252 struct start_args args =
254 moddepname,
255 moddep,
256 tlsmanydeps[t].modi,
257 tlsmanydeps[t].ndeps,
258 tlsmanydeps[t].deps
260 pthread_t t = xpthread_create (0, start, &args);
261 xpthread_join (t);
263 free (moddepname);
264 xdlclose (moddep);
267 for (int n = 1; n < nmods; n++)
268 if (mods[n] != 0)
269 unload_mod (n);
273 /* The following test check DTV gaps handling with shared libraries that has
274 invalid dependencies. It defines 5 different sets:
276 1. Single dependency:
277 mod0 -> invalid
278 2. Double dependency:
279 mod1 -> [mod2,invalid]
280 3. Double dependency with each dependency depent of another module:
281 mod3 -> [mod4,mod5] -> invalid
282 4. Long chain with one double dependency in the middle:
283 mod6 -> [mod7, mod8] -> mod12 -> invalid
284 5. Long chain with two double depedencies in the middle:
285 mod10 -> mod11 -> [mod12, mod13]
286 mod12 -> [mod14, invalid]
288 This does not cover all the possible gaps and configuration, but it
289 should check if different dynamic shared sets are placed correctly in
290 different gaps configurations. */
292 static void
293 do_test_invalid_dependency (bool bind_now)
295 static const int tlsmanydeps[] = { 0, 1, 3, 6, 10 };
297 /* The gap configuration is defined as a bitmap: the bit set represents a
298 loaded module prior the tests execution, while a bit unsed is a module
299 unloaded. Not all permtation will show gaps, but it is simpler than
300 define each one independently. */
301 for (uint32_t g = 0; g < 64; g++)
303 print_gap (g);
304 int nmods = nmodules (g);
306 int mods[nmods];
307 /* We use '0' as indication for a gap, to avoid the dlclose on iteration
308 cleanup. */
309 for (int n = 1; n < nmods; n++)
311 load_mod (n);
312 mods[n] = n;
314 for (int n = 1; n < nmods; n++)
316 if (!is_mod_set (g, n))
318 unload_mod (n);
319 mods[n] = 0;
323 for (int t = 0; t < array_length (tlsmanydeps); t++)
325 char *moddepname = xasprintf ("tst-tls-manydynamic%dmod-dep-bad.so",
326 tlsmanydeps[t]);
327 void *moddep;
328 if (bind_now)
330 moddep = dlopen (moddepname, RTLD_NOW);
331 TEST_VERIFY (moddep == 0);
333 else
334 moddep = dlopen (moddepname, RTLD_LAZY);
336 /* Access TLS in all loaded modules. */
337 pthread_t t = xpthread_create (0, start, NULL);
338 xpthread_join (t);
340 free (moddepname);
341 if (!bind_now)
342 xdlclose (moddep);
345 for (int n = 1; n < nmods; n++)
346 if (mods[n] != 0)
347 unload_mod (n);
351 static int
352 do_test (void)
354 do_test_no_depedency ();
355 do_test_dependency ();
356 do_test_invalid_dependency (true);
357 do_test_invalid_dependency (false);
359 return 0;
362 #include <support/test-driver.c>