elf: Ignore loader debug env vars for setuid
[glibc.git] / elf / tst-dlopen-nodelete-reloc.c
blob2ff3087eed8932ec41bcbcc94821cbf9ad490d36
1 /* Test interactions of dlopen, NODELETE, and relocations.
2 Copyright (C) 2019-2023 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 <https://www.gnu.org/licenses/>. */
19 /* This test exercises NODELETE propagation due to data relocations
20 and unique symbols, and the interaction with already-loaded
21 objects. Some test objects are written in C++, to produce unique
22 symbol definitions.
24 First test: Global scope variant, data relocation as the NODELETE
25 trigger. mod1 is loaded first with a separate dlopen call.
27 mod2 ---(may_finalize_mod1 relocation dependency)---> mod1
28 (NODELETE) (marked as NODELETE)
30 Second test: Local scope variant, data relocation. mod3 is loaded
31 first, then mod5.
33 mod5 ---(DT_NEEDED)---> mod4 ---(DT_NEEDED)---> mod3
34 (NODELETE) (not NODELETE) ^
35 \ / (marked as
36 `--(may_finalize_mod3 relocation dependency)--/ NODELETE)
38 Third test: Shared local scope with unique symbol. mod6 is loaded
39 first, then mod7. No explicit dependencies between the two
40 objects, so first object has to be opened with RTLD_GLOBAL.
42 mod7 ---(unique symbol)---> mod6
43 (marked as NODELETE)
45 Forth test: Non-shared scopes with unique symbol. mod8 and mod10
46 are loaded from the main program. mod8 loads mod9 from an ELF
47 constructor, mod10 loads mod11. There are no DT_NEEDED
48 dependencies. mod9 is promoted to the global scope form the main
49 program. The unique symbol dependency is:
51 mod9 ---(unique symbol)---> mod11
52 (marked as NODELETE)
54 Fifth test: Shared local scope with unique symbol, like test 3, but
55 this time, there is also a DT_NEEDED dependency (so no RTLD_GLOBAL
56 needed):
58 DT_NEEDED
59 mod13 ---(unique symbol)---> mod12
60 (marked as NODELETE)
62 Sixth test: NODELETE status is retained after relocation failure
63 with unique symbol dependency. The object graph ensures that the
64 unique symbol binding is processed before the dlopen failure.
66 DT_NEEDED
67 mod17 --(DT_NEEDED)--> mod15 --(unique symbol)--> mod14
68 \ ^ (RTLD_NODELETE)
69 \ (DT_NEEDED)
70 \ |
71 `---(DT_NEEDED)--> mod16
72 (fails to relocate)
74 mod14 is loaded first, and the loading mod17 is attempted.
75 mod14 must remain NODELETE after opening mod17 failed. */
77 #include <stdio.h>
78 #include <string.h>
79 #include <stdbool.h>
80 #include <support/check.h>
81 #include <support/xdlfcn.h>
83 static int
84 do_test (void)
86 /* First case: global scope, regular data symbol. Open the object
87 which is not NODELETE initially. */
88 void *mod1 = xdlopen ("tst-dlopen-nodelete-reloc-mod1.so",
89 RTLD_NOW | RTLD_GLOBAL);
90 /* This is used to indicate that the ELF destructor may be
91 called. */
92 bool *may_finalize_mod1 = xdlsym (mod1, "may_finalize_mod1");
93 /* Open the NODELETE object. */
94 void *mod2 = xdlopen ("tst-dlopen-nodelete-reloc-mod2.so", RTLD_NOW);
95 /* This has no effect because the DSO is directly marked as
96 NODELETE. */
97 xdlclose (mod2);
98 /* This has no effect because the DSO has been indirectly marked as
99 NODELETE due to a relocation dependency. */
100 xdlclose (mod1);
102 /* Second case: local scope, regular data symbol. Open the object
103 which is not NODELETE initially. */
104 void *mod3 = xdlopen ("tst-dlopen-nodelete-reloc-mod3.so", RTLD_NOW);
105 bool *may_finalize_mod3 = xdlsym (mod3, "may_finalize_mod3");
106 /* Open the NODELETE object. */
107 void *mod5 = xdlopen ("tst-dlopen-nodelete-reloc-mod5.so", RTLD_NOW);
108 /* Again those have no effect because of NODELETE. */
109 xdlclose (mod5);
110 xdlclose (mod3);
112 /* Third case: Unique symbol. */
113 void *mod6 = xdlopen ("tst-dlopen-nodelete-reloc-mod6.so",
114 RTLD_NOW | RTLD_GLOBAL);
115 bool *may_finalize_mod6 = xdlsym (mod6, "may_finalize_mod6");
116 void *mod7 = xdlopen ("tst-dlopen-nodelete-reloc-mod7.so", RTLD_NOW);
117 bool *may_finalize_mod7 = xdlsym (mod7, "may_finalize_mod7");
118 /* This should not have any effect because of the unique symbol and
119 the resulting NODELETE status. */
120 xdlclose (mod6);
121 /* mod7 is not NODELETE and can be closed. */
122 *may_finalize_mod7 = true;
123 xdlclose (mod7);
125 /* Fourth case: Unique symbol, indirect loading. */
126 void *mod8 = xdlopen ("tst-dlopen-nodelete-reloc-mod8.so", RTLD_NOW);
127 /* Also promote to global scope. */
128 void *mod9 = xdlopen ("tst-dlopen-nodelete-reloc-mod9.so",
129 RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
130 bool *may_finalize_mod9 = xdlsym (mod9, "may_finalize_mod9");
131 xdlclose (mod9); /* Drop mod9 reference. */
132 void *mod10 = xdlopen ("tst-dlopen-nodelete-reloc-mod10.so", RTLD_NOW);
133 void *mod11 = xdlopen ("tst-dlopen-nodelete-reloc-mod11.so",
134 RTLD_NOW | RTLD_NOLOAD);
135 bool *may_finalize_mod11 = xdlsym (mod11, "may_finalize_mod11");
136 xdlclose (mod11); /* Drop mod11 reference. */
137 /* mod11 is not NODELETE and can be closed. */
138 *may_finalize_mod11 = true;
139 /* Trigger closing of mod11, too. */
140 xdlclose (mod10);
141 /* Does not trigger closing of mod9. */
142 xdlclose (mod8);
144 /* Fifth case: Unique symbol, with DT_NEEDED dependency. */
145 void *mod12 = xdlopen ("tst-dlopen-nodelete-reloc-mod12.so", RTLD_NOW);
146 bool *may_finalize_mod12 = xdlsym (mod12, "may_finalize_mod12");
147 void *mod13 = xdlopen ("tst-dlopen-nodelete-reloc-mod13.so", RTLD_NOW);
148 bool *may_finalize_mod13 = xdlsym (mod13, "may_finalize_mod13");
149 /* This should not have any effect because of the unique symbol. */
150 xdlclose (mod12);
151 /* mod13 is not NODELETE and can be closed. */
152 *may_finalize_mod13 = true;
153 xdlclose (mod13);
155 /* Sixth case: Unique symbol binding must not cause loss of NODELETE
156 status. */
157 void *mod14 = xdlopen ("tst-dlopen-nodelete-reloc-mod14.so",
158 RTLD_NOW | RTLD_NODELETE);
159 bool *may_finalize_mod14 = xdlsym (mod14, "may_finalize_mod14");
160 TEST_VERIFY (dlopen ("tst-dlopen-nodelete-reloc-mod17.so", RTLD_NOW)
161 == NULL);
162 const char *message = dlerror ();
163 printf ("info: test 6 message: %s\n", message);
164 /* This must not close the object, it must still be NODELETE. */
165 xdlclose (mod14);
166 xdlopen ("tst-dlopen-nodelete-reloc-mod14.so", RTLD_NOW | RTLD_NOLOAD);
168 /* Prepare for process exit. Destructors for NODELETE objects will
169 be invoked. */
170 *may_finalize_mod1 = true;
171 *may_finalize_mod3 = true;
172 *may_finalize_mod6 = true;
173 *may_finalize_mod9 = true;
174 *may_finalize_mod12 = true;
175 *may_finalize_mod14 = true;
176 return 0;
179 #include <support/test-driver.c>