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 36enum order { 37 DEF_USE_EAGER, 38 DEF_USE_LAZY, 39 USE_DEF, 40 USE_DEF_NOLOAD, 41}; 42 43static void 44tls_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)); 72lazy: 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 84ATF_TC(dynamic_abusedef); 85ATF_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} 90ATF_TC_BODY(dynamic_abusedef, tc) 91{ 92 tls_extern("libh_def_dynamic.so", "libh_abuse_dynamic.so", USE_DEF); 93} 94 95ATF_TC(dynamic_abusedefnoload); 96ATF_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} 101ATF_TC_BODY(dynamic_abusedefnoload, tc) 102{ 103 tls_extern("libh_def_dynamic.so", "libh_abuse_dynamic.so", 104 USE_DEF_NOLOAD); 105} 106 107ATF_TC(dynamic_defabuse_eager); 108ATF_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} 113ATF_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 125ATF_TC(dynamic_defabuse_lazy); 126ATF_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} 131ATF_TC_BODY(dynamic_defabuse_lazy, tc) 132{ 133 tls_extern("libh_def_dynamic.so", "libh_abuse_dynamic.so", 134 DEF_USE_LAZY); 135} 136 137ATF_TC(dynamic_defuse_eager); 138ATF_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} 143ATF_TC_BODY(dynamic_defuse_eager, tc) 144{ 145 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 146 DEF_USE_EAGER); 147} 148 149ATF_TC(dynamic_defuse_lazy); 150ATF_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} 155ATF_TC_BODY(dynamic_defuse_lazy, tc) 156{ 157 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 158 DEF_USE_LAZY); 159} 160 161ATF_TC(dynamic_usedef); 162ATF_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} 167ATF_TC_BODY(dynamic_usedef, tc) 168{ 169 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 170 USE_DEF); 171} 172 173ATF_TC(dynamic_usedefnoload); 174ATF_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} 179ATF_TC_BODY(dynamic_usedefnoload, tc) 180{ 181 tls_extern("libh_def_dynamic.so", "libh_use_dynamic.so", 182 USE_DEF_NOLOAD); 183} 184 185ATF_TC(static_abusedef); 186ATF_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} 191ATF_TC_BODY(static_abusedef, tc) 192{ 193 tls_extern("libh_def_static.so", "libh_abuse_static.so", USE_DEF); 194} 195 196ATF_TC(static_abusedefnoload); 197ATF_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} 202ATF_TC_BODY(static_abusedefnoload, tc) 203{ 204 tls_extern("libh_def_static.so", "libh_abuse_static.so", 205 USE_DEF_NOLOAD); 206} 207 208ATF_TC(static_defabuse_eager); 209ATF_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} 214ATF_TC_BODY(static_defabuse_eager, tc) 215{ 216 tls_extern("libh_def_static.so", "libh_abuse_static.so", 217 DEF_USE_EAGER); 218} 219 220ATF_TC(static_defabuse_lazy); 221ATF_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} 226ATF_TC_BODY(static_defabuse_lazy, tc) 227{ 228 tls_extern("libh_def_static.so", "libh_abuse_static.so", 229 DEF_USE_LAZY); 230} 231 232ATF_TC(static_defuse_eager); 233ATF_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} 238ATF_TC_BODY(static_defuse_eager, tc) 239{ 240 tls_extern("libh_def_static.so", "libh_use_static.so", 241 DEF_USE_EAGER); 242} 243 244ATF_TC(static_defuse_lazy); 245ATF_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} 250ATF_TC_BODY(static_defuse_lazy, tc) 251{ 252 tls_extern("libh_def_static.so", "libh_use_static.so", 253 DEF_USE_LAZY); 254} 255 256ATF_TC(static_usedef); 257ATF_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} 262ATF_TC_BODY(static_usedef, tc) 263{ 264 tls_extern("libh_def_static.so", "libh_use_static.so", 265 USE_DEF); 266} 267 268ATF_TC(static_usedefnoload); 269ATF_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} 274ATF_TC_BODY(static_usedefnoload, tc) 275{ 276 tls_extern("libh_def_static.so", "libh_use_static.so", 277 USE_DEF_NOLOAD); 278} 279 280ATF_TC(onlydef_dynamic_static_ctor); 281ATF_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} 286ATF_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 295ATF_TC(onlydef_dynamic_static_eager); 296ATF_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} 301ATF_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 313ATF_TC(onlydef_dynamic_static_lazy); 314ATF_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} 319ATF_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 336ATF_TC(onlydef_static_dynamic_eager); 337ATF_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} 343ATF_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 361ATF_TC(onlydef_static_dynamic_lazy); 362ATF_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} 367ATF_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 385ATF_TC(opencloseloop_use); 386ATF_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} 391ATF_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 442ATF_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