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