Home | History | Annotate | Line # | Download | only in ld.elf_so
      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