1 /* Test interactions of dlopen, NODELETE, and relocations.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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/>. */
18
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.
23
24 First test: Global scope variant, data relocation as the NODELETE
25 trigger. mod1 is loaded first with a separate dlopen call.
26
27 mod2 ---(may_finalize_mod1 relocation dependency)---> mod1
28 (NODELETE) (marked as NODELETE)
29
30 Second test: Local scope variant, data relocation. mod3 is loaded
31 first, then mod5.
32
33 mod5 ---(DT_NEEDED)---> mod4 ---(DT_NEEDED)---> mod3
34 (NODELETE) (not NODELETE) ^
35 \ / (marked as
36 `--(may_finalize_mod3 relocation dependency)--/ NODELETE)
37
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.
41
42 mod7 ---(unique symbol)---> mod6
43 (marked as NODELETE)
44
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:
50
51 mod9 ---(unique symbol)---> mod11
52 (marked as NODELETE)
53
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):
57
58 DT_NEEDED
59 mod13 ---(unique symbol)---> mod12
60 (marked as NODELETE)
61
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.
65
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)
73
74 mod14 is loaded first, and the loading mod17 is attempted.
75 mod14 must remain NODELETE after opening mod17 failed. */
76
77 #include <stdio.h>
78 #include <string.h>
79 #include <stdbool.h>
80 #include <support/check.h>
81 #include <support/xdlfcn.h>
82
83 static int
do_test(void)84 do_test (void)
85 {
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);
101
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);
111
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);
124
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);
143
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);
154
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);
167
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;
177 }
178
179 #include <support/test-driver.c>
180