1 /* $NetBSD: t_tls_extern.c,v 1.16 2024/07/23 18:11:53 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2023 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 31 #include <atf-c.h> 32 #include <dlfcn.h> 33 34 #define ATF_REQUIRE_DL(x) ATF_REQUIRE_MSG((x) != 0, "%s: %s", #x, dlerror()) 35 36 enum order { 37 DEF_USE_EAGER, 38 DEF_USE_LAZY, 39 USE_DEF, 40 USE_DEF_NOLOAD, 41 }; 42 43 static void 44 tls_extern(const char *libdef, const char *libuse, enum order order) 45 { 46 void *def, *use; 47 int *(*fdef)(void), *(*fuse)(void); 48 int *pdef, *puse; 49 50 (void)dlerror(); 51 52 switch (order) { 53 case DEF_USE_EAGER: 54 ATF_REQUIRE_DL(def = dlopen(libdef, 0)); 55 ATF_REQUIRE_DL(fdef = dlsym(def, "fdef")); 56 pdef = (*fdef)(); 57 ATF_REQUIRE_DL(use = dlopen(libuse, 0)); 58 ATF_REQUIRE_DL(fuse = dlsym(use, "fuse")); 59 puse = (*fuse)(); 60 break; 61 case DEF_USE_LAZY: 62 ATF_REQUIRE_DL(def = dlopen(libdef, 0)); 63 ATF_REQUIRE_DL(use = dlopen(libuse, 0)); 64 goto lazy; 65 case USE_DEF: 66 ATF_REQUIRE_DL(use = dlopen(libuse, 0)); 67 ATF_REQUIRE_DL(def = dlopen(libdef, 0)); 68 goto lazy; 69 case USE_DEF_NOLOAD: 70 ATF_REQUIRE_DL(use = dlopen(libuse, 0)); 71 ATF_REQUIRE_DL(def = dlopen(libdef, RTLD_NOLOAD)); 72 lazy: ATF_REQUIRE_DL(fdef = dlsym(def, "fdef")); 73 ATF_REQUIRE_DL(fuse = dlsym(use, "fuse")); 74 pdef = (*fdef)(); 75 puse = (*fuse)(); 76 break; 77 } 78 79 ATF_CHECK_EQ_MSG(pdef, puse, 80 "%p in defining library != %p in using library", 81 pdef, puse); 82 } 83 84 ATF_TC(dynamic_abusedef); 85 ATF_TC_HEAD(dynamic_abusedef, tc) 86 { 87 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 88 " loading static use than dynamic def"); 89 } 90 ATF_TC_BODY(dynamic_abusedef, tc) 91 { 92 tls_extern("libh_def_dynamic.so", "libh_abuse_dynamic.so", USE_DEF); 93 } 94 95 ATF_TC(dynamic_abusedefnoload); 96 ATF_TC_HEAD(dynamic_abusedefnoload, tc) 97 { 98 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 99 " loading static use then dynamic def with RTLD_NOLOAD"); 100 } 101 ATF_TC_BODY(dynamic_abusedefnoload, tc) 102 { 103 tls_extern("libh_def_dynamic.so", "libh_abuse_dynamic.so", 104 USE_DEF_NOLOAD); 105 } 106 107 ATF_TC(dynamic_defabuse_eager); 108 ATF_TC_HEAD(dynamic_defabuse_eager, tc) 109 { 110 atf_tc_set_md_var(tc, "descr", "dlopen refuses extern __thread for TLS," 111 " loading dynamic def then static use eagerly"); 112 } 113 ATF_TC_BODY(dynamic_defabuse_eager, tc) 114 { 115 void *def; 116 int *(*fdef)(void); 117 118 ATF_REQUIRE_DL(def = dlopen("libh_def_dynamic.so", 0)); 119 ATF_REQUIRE_DL(fdef = dlsym(def, "fdef")); 120 (void)(*fdef)(); 121 ATF_CHECK_EQ_MSG(NULL, dlopen("libh_abuse_dynamic.so", 0), 122 "dlopen failed to detect static-then-dynamic abuse"); 123 } 124 125 ATF_TC(dynamic_defabuse_lazy); 126 ATF_TC_HEAD(dynamic_defabuse_lazy, tc) 127 { 128 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 129 " loading dynamic def then static use lazily"); 130 } 131 ATF_TC_BODY(dynamic_defabuse_lazy, tc) 132 { 133 tls_extern("libh_def_dynamic.so", "libh_abuse_dynamic.so", 134 DEF_USE_LAZY); 135 } 136 137 ATF_TC(dynamic_defuse_eager); 138 ATF_TC_HEAD(dynamic_defuse_eager, tc) 139 { 140 atf_tc_set_md_var(tc, "descr", "extern __thread for dynamic TLS works," 141 " loading def then use eagerly"); 142 } 143 ATF_TC_BODY(dynamic_defuse_eager, tc) 144 { 145 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 146 DEF_USE_EAGER); 147 } 148 149 ATF_TC(dynamic_defuse_lazy); 150 ATF_TC_HEAD(dynamic_defuse_lazy, tc) 151 { 152 atf_tc_set_md_var(tc, "descr", "extern __thread for dynamic TLS works," 153 " loading def then use lazyly"); 154 } 155 ATF_TC_BODY(dynamic_defuse_lazy, tc) 156 { 157 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 158 DEF_USE_LAZY); 159 } 160 161 ATF_TC(dynamic_usedef); 162 ATF_TC_HEAD(dynamic_usedef, tc) 163 { 164 atf_tc_set_md_var(tc, "descr", "extern __thread for dynamic TLS works," 165 " loading use then def"); 166 } 167 ATF_TC_BODY(dynamic_usedef, tc) 168 { 169 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 170 USE_DEF); 171 } 172 173 ATF_TC(dynamic_usedefnoload); 174 ATF_TC_HEAD(dynamic_usedefnoload, tc) 175 { 176 atf_tc_set_md_var(tc, "descr", "extern __thread for dynamic TLS works," 177 " loading use then def with RTLD_NOLOAD"); 178 } 179 ATF_TC_BODY(dynamic_usedefnoload, tc) 180 { 181 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 182 USE_DEF_NOLOAD); 183 } 184 185 ATF_TC(static_abusedef); 186 ATF_TC_HEAD(static_abusedef, tc) 187 { 188 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 189 " loading dynamic use then static def"); 190 } 191 ATF_TC_BODY(static_abusedef, tc) 192 { 193 tls_extern("libh_def_static.so", "libh_abuse_static.so", USE_DEF); 194 } 195 196 ATF_TC(static_abusedefnoload); 197 ATF_TC_HEAD(static_abusedefnoload, tc) 198 { 199 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 200 " loading dynamic use then static def with RTLD_NOLOAD"); 201 } 202 ATF_TC_BODY(static_abusedefnoload, tc) 203 { 204 tls_extern("libh_def_static.so", "libh_abuse_static.so", 205 USE_DEF_NOLOAD); 206 } 207 208 ATF_TC(static_defabuse_eager); 209 ATF_TC_HEAD(static_defabuse_eager, tc) 210 { 211 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 212 " loading static def then dynamic use eagerly"); 213 } 214 ATF_TC_BODY(static_defabuse_eager, tc) 215 { 216 tls_extern("libh_def_static.so", "libh_abuse_static.so", 217 DEF_USE_EAGER); 218 } 219 220 ATF_TC(static_defabuse_lazy); 221 ATF_TC_HEAD(static_defabuse_lazy, tc) 222 { 223 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 224 " loading static def then dynamic use lazyly"); 225 } 226 ATF_TC_BODY(static_defabuse_lazy, tc) 227 { 228 tls_extern("libh_def_static.so", "libh_abuse_static.so", 229 DEF_USE_LAZY); 230 } 231 232 ATF_TC(static_defuse_eager); 233 ATF_TC_HEAD(static_defuse_eager, tc) 234 { 235 atf_tc_set_md_var(tc, "descr", "extern __thread for static TLS works," 236 " loading def then use eagerly"); 237 } 238 ATF_TC_BODY(static_defuse_eager, tc) 239 { 240 tls_extern("libh_def_static.so", "libh_use_static.so", 241 DEF_USE_EAGER); 242 } 243 244 ATF_TC(static_defuse_lazy); 245 ATF_TC_HEAD(static_defuse_lazy, tc) 246 { 247 atf_tc_set_md_var(tc, "descr", "extern __thread for static TLS works," 248 " loading def then use lazyly"); 249 } 250 ATF_TC_BODY(static_defuse_lazy, tc) 251 { 252 tls_extern("libh_def_static.so", "libh_use_static.so", 253 DEF_USE_LAZY); 254 } 255 256 ATF_TC(static_usedef); 257 ATF_TC_HEAD(static_usedef, tc) 258 { 259 atf_tc_set_md_var(tc, "descr", "extern __thread for static TLS works," 260 " loading use then def"); 261 } 262 ATF_TC_BODY(static_usedef, tc) 263 { 264 tls_extern("libh_def_static.so", "libh_use_static.so", 265 USE_DEF); 266 } 267 268 ATF_TC(static_usedefnoload); 269 ATF_TC_HEAD(static_usedefnoload, tc) 270 { 271 atf_tc_set_md_var(tc, "descr", "extern __thread for static TLS works," 272 " loading use then def with RTLD_NOLOAD"); 273 } 274 ATF_TC_BODY(static_usedefnoload, tc) 275 { 276 tls_extern("libh_def_static.so", "libh_use_static.so", 277 USE_DEF_NOLOAD); 278 } 279 280 ATF_TC(onlydef_dynamic_static_ctor); 281 ATF_TC_HEAD(onlydef_dynamic_static_ctor, tc) 282 { 283 atf_tc_set_md_var(tc, "descr", "definition-only library," 284 " dynamic load and use in ctor, then static load fails"); 285 } 286 ATF_TC_BODY(onlydef_dynamic_static_ctor, tc) 287 { 288 289 ATF_REQUIRE_DL(dlopen("libh_onlydef.so", 0)); 290 ATF_REQUIRE_DL(dlopen("libh_onlyctor_dynamic.so", 0)); 291 ATF_CHECK_EQ_MSG(NULL, dlopen("libh_onlyuse_static.so", 0), 292 "dlopen failed to detect dynamic-then-static abuse"); 293 } 294 295 ATF_TC(onlydef_dynamic_static_eager); 296 ATF_TC_HEAD(onlydef_dynamic_static_eager, tc) 297 { 298 atf_tc_set_md_var(tc, "descr", "definition-only library," 299 " dynamic load and use, then static load fails"); 300 } 301 ATF_TC_BODY(onlydef_dynamic_static_eager, tc) 302 { 303 void *use_dynamic; 304 int *(*fdynamic)(void); 305 306 ATF_REQUIRE_DL(use_dynamic = dlopen("libh_onlyuse_dynamic.so", 0)); 307 ATF_REQUIRE_DL(fdynamic = dlsym(use_dynamic, "fdynamic")); 308 (void)(*fdynamic)(); 309 ATF_CHECK_EQ_MSG(NULL, dlopen("libh_onlyuse_static.so", 0), 310 "dlopen failed to detect dynamic-then-static abuse"); 311 } 312 313 ATF_TC(onlydef_dynamic_static_lazy); 314 ATF_TC_HEAD(onlydef_dynamic_static_lazy, tc) 315 { 316 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 317 " with definition-only library, dynamic and static load and use"); 318 } 319 ATF_TC_BODY(onlydef_dynamic_static_lazy, tc) 320 { 321 void *use_dynamic, *use_static; 322 int *(*fdynamic)(void), *(*fstatic)(void); 323 int *pdynamic, *pstatic; 324 325 ATF_REQUIRE_DL(use_dynamic = dlopen("libh_onlyuse_dynamic.so", 0)); 326 ATF_REQUIRE_DL(use_static = dlopen("libh_onlyuse_static.so", 0)); 327 ATF_REQUIRE_DL(fdynamic = dlsym(use_dynamic, "fdynamic")); 328 ATF_REQUIRE_DL(fstatic = dlsym(use_static, "fstatic")); 329 pdynamic = (*fdynamic)(); 330 pstatic = (*fstatic)(); 331 ATF_CHECK_EQ_MSG(pdynamic, pstatic, 332 "%p in dynamic tls user != %p in static tls user", 333 pdynamic, pstatic); 334 } 335 336 ATF_TC(onlydef_static_dynamic_eager); 337 ATF_TC_HEAD(onlydef_static_dynamic_eager, tc) 338 { 339 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 340 " with definition-only library," 341 " static load and use, then dynamic load and use"); 342 } 343 ATF_TC_BODY(onlydef_static_dynamic_eager, tc) 344 { 345 void *use_static, *use_dynamic; 346 int *(*fstatic)(void), *(*fdynamic)(void); 347 int *pstatic, *pdynamic; 348 349 ATF_REQUIRE_DL(dlopen("libh_onlydef.so", 0)); 350 ATF_REQUIRE_DL(use_static = dlopen("libh_onlyuse_static.so", 0)); 351 ATF_REQUIRE_DL(fstatic = dlsym(use_static, "fstatic")); 352 pstatic = (*fstatic)(); 353 ATF_REQUIRE_DL(use_dynamic = dlopen("libh_onlyuse_dynamic.so", 0)); 354 ATF_REQUIRE_DL(fdynamic = dlsym(use_dynamic, "fdynamic")); 355 pdynamic = (*fdynamic)(); 356 ATF_CHECK_EQ_MSG(pstatic, pdynamic, 357 "%p in static tls user != %p in dynamic tls user", 358 pstatic, pdynamic); 359 } 360 361 ATF_TC(onlydef_static_dynamic_lazy); 362 ATF_TC_HEAD(onlydef_static_dynamic_lazy, tc) 363 { 364 atf_tc_set_md_var(tc, "descr", "extern __thread for TLS works," 365 " with definition-only library, static and dynamic load and use"); 366 } 367 ATF_TC_BODY(onlydef_static_dynamic_lazy, tc) 368 { 369 void *use_static, *use_dynamic; 370 int *(*fstatic)(void), *(*fdynamic)(void); 371 int *pstatic, *pdynamic; 372 373 ATF_REQUIRE_DL(dlopen("libh_onlydef.so", 0)); 374 ATF_REQUIRE_DL(use_static = dlopen("libh_onlyuse_static.so", 0)); 375 ATF_REQUIRE_DL(use_dynamic = dlopen("libh_onlyuse_dynamic.so", 0)); 376 ATF_REQUIRE_DL(fstatic = dlsym(use_static, "fstatic")); 377 ATF_REQUIRE_DL(fdynamic = dlsym(use_dynamic, "fdynamic")); 378 pstatic = (*fstatic)(); 379 pdynamic = (*fdynamic)(); 380 ATF_CHECK_EQ_MSG(pstatic, pdynamic, 381 "%p in static tls user != %p in dynamic tls user", 382 pstatic, pdynamic); 383 } 384 385 ATF_TC(opencloseloop_use); 386 ATF_TC_HEAD(opencloseloop_use, tc) 387 { 388 atf_tc_set_md_var(tc, "descr", "Testing opening and closing in a loop," 389 " then opening and using dynamic TLS"); 390 } 391 ATF_TC_BODY(opencloseloop_use, tc) 392 { 393 unsigned i; 394 void *def, *use; 395 int *(*fdef)(void), *(*fuse)(void); 396 int *pdef, *puse; 397 398 /* 399 * Open and close the definition library repeatedly. This 400 * should trigger allocation of many DTV offsets, which are 401 * (currently) not recycled, so the required DTV offsets should 402 * become very long -- pages past what is actually allocated 403 * before we attempt to use it. 404 * 405 * This way, we will exercise the wrong-way-conditional fast 406 * path of PR lib/58154. 407 */ 408 for (i = sysconf(_SC_PAGESIZE); i --> 0;) { 409 ATF_REQUIRE_DL(def = dlopen("libh_def_dynamic.so", 0)); 410 ATF_REQUIRE_EQ_MSG(dlclose(def), 0, 411 "dlclose(def): %s", dlerror()); 412 } 413 414 /* 415 * Now open the definition library and keep it open. 416 */ 417 ATF_REQUIRE_DL(def = dlopen("libh_def_dynamic.so", 0)); 418 ATF_REQUIRE_DL(fdef = dlsym(def, "fdef")); 419 420 /* 421 * Open libraries that use the definition and verify they 422 * observe the same pointer. 423 */ 424 ATF_REQUIRE_DL(use = dlopen("libh_use_dynamic.so", 0)); 425 ATF_REQUIRE_DL(fuse = dlsym(use, "fuse")); 426 pdef = (*fdef)(); 427 puse = (*fuse)(); 428 ATF_CHECK_EQ_MSG(pdef, puse, 429 "%p in defining library != %p in using library", 430 pdef, puse); 431 432 /* 433 * Also verify the pointer can be used. 434 */ 435 *pdef = 123; 436 *puse = 456; 437 ATF_CHECK_EQ_MSG(*pdef, *puse, 438 "%d in defining library != %d in using library", 439 *pdef, *puse); 440 } 441 442 ATF_TP_ADD_TCS(tp) 443 { 444 445 ATF_TP_ADD_TC(tp, dynamic_abusedef); 446 ATF_TP_ADD_TC(tp, dynamic_abusedefnoload); 447 ATF_TP_ADD_TC(tp, dynamic_defabuse_eager); 448 ATF_TP_ADD_TC(tp, dynamic_defabuse_lazy); 449 ATF_TP_ADD_TC(tp, dynamic_defuse_eager); 450 ATF_TP_ADD_TC(tp, dynamic_defuse_lazy); 451 ATF_TP_ADD_TC(tp, dynamic_usedef); 452 ATF_TP_ADD_TC(tp, dynamic_usedefnoload); 453 ATF_TP_ADD_TC(tp, onlydef_dynamic_static_ctor); 454 ATF_TP_ADD_TC(tp, onlydef_dynamic_static_eager); 455 ATF_TP_ADD_TC(tp, onlydef_dynamic_static_lazy); 456 ATF_TP_ADD_TC(tp, onlydef_static_dynamic_eager); 457 ATF_TP_ADD_TC(tp, onlydef_static_dynamic_lazy); 458 ATF_TP_ADD_TC(tp, opencloseloop_use); 459 ATF_TP_ADD_TC(tp, static_abusedef); 460 ATF_TP_ADD_TC(tp, static_abusedefnoload); 461 ATF_TP_ADD_TC(tp, static_defabuse_eager); 462 ATF_TP_ADD_TC(tp, static_defabuse_lazy); 463 ATF_TP_ADD_TC(tp, static_defuse_eager); 464 ATF_TP_ADD_TC(tp, static_defuse_lazy); 465 ATF_TP_ADD_TC(tp, static_usedef); 466 ATF_TP_ADD_TC(tp, static_usedefnoload); 467 return atf_no_error(); 468 } 469