]> sourceware.org Git - glibc.git/blame - elf/dl-deps.c
support: Use macros for *stat wrappers
[glibc.git] / elf / dl-deps.c
CommitLineData
efec1d0c 1/* Load the dependencies of a mapped object.
dff8da6b 2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
afd4eb37
UD
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
41bdb6e2
AJ
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.
afd4eb37
UD
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
41bdb6e2 13 Lesser General Public License for more details.
afd4eb37 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
efec1d0c 18
385b4cf4 19#include <atomic.h>
dc5efe83 20#include <assert.h>
efec1d0c 21#include <dlfcn.h>
a853022c 22#include <errno.h>
8e17ea58 23#include <libintl.h>
32e6df36 24#include <stddef.h>
efec1d0c 25#include <stdlib.h>
ca34d7a7 26#include <string.h>
06535ae9 27#include <unistd.h>
dc5efe83 28#include <sys/param.h>
a42195db 29#include <ldsodefs.h>
92d6aa85 30#include <scratch_buffer.h>
a853022c 31
dc5efe83 32#include <dl-dst.h>
1522c368
UD
33
34/* Whether an shared object references one or more auxiliary objects
35 is signaled by the AUXTAG entry in l_info. */
b0982c4a 36#define AUXTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
1522c368 37 + DT_EXTRATAGIDX (DT_AUXILIARY))
f41c8091
UD
38/* Whether an shared object references one or more auxiliary objects
39 is signaled by the AUXTAG entry in l_info. */
b0982c4a 40#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
f41c8091 41 + DT_EXTRATAGIDX (DT_FILTER))
1522c368
UD
42
43
44/* When loading auxiliary objects we must ignore errors. It's ok if
45 an object is missing. */
993b3242 46struct openaux_args
1522c368
UD
47 {
48 /* The arguments to openaux. */
49 struct link_map *map;
50 int trace_mode;
87837aac 51 int open_mode;
1522c368 52 const char *strtab;
dc5efe83 53 const char *name;
993b3242 54
1522c368
UD
55 /* The return value of openaux. */
56 struct link_map *aux;
57 };
993b3242
UD
58
59static void
60openaux (void *a)
61{
62 struct openaux_args *args = (struct openaux_args *) a;
63
8e9f92e9 64 args->aux = _dl_map_object (args->map, args->name,
154d10bd
UD
65 (args->map->l_type == lt_executable
66 ? lt_library : args->map->l_type),
c0f62c56
UD
67 args->trace_mode, args->open_mode,
68 args->map->l_ns);
993b3242
UD
69}
70
80d9c5f0 71/* We use a very special kind of list to track the path
1522c368 72 through the list of loaded shared objects. We have to
80d9c5f0 73 produce a flat list with unique members of all involved objects.
1522c368
UD
74*/
75struct list
76 {
77 int done; /* Nonzero if this map was processed. */
78 struct link_map *map; /* The data. */
ac55a25b 79 struct list *next; /* Elements for normal list. */
1522c368
UD
80 };
81
82
dc5efe83
UD
83/* Macro to expand DST. It is an macro since we use `alloca'. */
84#define expand_dst(l, str, fatal) \
85 ({ \
86 const char *__str = (str); \
87 const char *__result = __str; \
5aad5f61 88 size_t __dst_cnt = _dl_dst_count (__str); \
dc5efe83 89 \
ac55a25b 90 if (__dst_cnt != 0) \
dc5efe83 91 { \
06535ae9
UD
92 char *__newp; \
93 \
94 /* DST must not appear in SUID/SGID programs. */ \
6bc6bd3b 95 if (__libc_enable_secure) \
154d10bd 96 _dl_signal_error (0, __str, NULL, N_("\
87837aac 97DST not allowed in SUID/SGID programs")); \
06535ae9
UD
98 \
99 __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \
ac55a25b 100 __dst_cnt)); \
dc5efe83 101 \
2bd86632 102 __result = _dl_dst_substitute (l, __str, __newp); \
dc5efe83
UD
103 \
104 if (*__result == '\0') \
105 { \
106 /* The replacement for the DST is not known. We can't \
107 processed. */ \
108 if (fatal) \
154d10bd 109 _dl_signal_error (0, __str, NULL, N_("\
11bf311e 110empty dynamic string token substitution")); \
dc5efe83
UD
111 else \
112 { \
113 /* This is for DT_AUXILIARY. */ \
a1ffb40e 114 if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) \
154d10bd 115 _dl_debug_printf (N_("\
7969407a
UD
116cannot load auxiliary `%s' because of empty dynamic string token " \
117 "substitution\n"), __str); \
dc5efe83
UD
118 continue; \
119 } \
120 } \
121 } \
122 \
123 __result; })
124
06210a44
KS
125static void
126preload (struct list *known, unsigned int *nlist, struct link_map *map)
127{
128 known[*nlist].done = 0;
129 known[*nlist].map = map;
130 known[*nlist].next = &known[*nlist + 1];
131
132 ++*nlist;
133 /* We use `l_reserved' as a mark bit to detect objects we have
134 already put in the search list and avoid adding duplicate
135 elements later in the list. */
136 map->l_reserved = 1;
137}
dc5efe83 138
d9cb1a7d 139void
2064087b 140_dl_map_object_deps (struct link_map *map,
46ec036d 141 struct link_map **preloads, unsigned int npreloads,
87837aac 142 int trace_mode, int open_mode)
efec1d0c 143{
db2f05ba 144 struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
80d9c5f0
UD
145 struct list *runp, *tail;
146 unsigned int nlist, i;
c77a4478
UD
147 /* Object name. */
148 const char *name;
149 int errno_saved;
150 int errno_reason;
2449ae7b 151 struct dl_exception exception;
1522c368 152
1522c368
UD
153 /* No loaded object so far. */
154 nlist = 0;
2064087b 155
1522c368 156 /* First load MAP itself. */
06210a44 157 preload (known, &nlist, map);
df4ef2ab
UD
158
159 /* Add the preloaded items after MAP but before any of its dependencies. */
160 for (i = 0; i < npreloads; ++i)
06210a44 161 preload (known, &nlist, preloads[i]);
df4ef2ab 162
8a523922 163 /* Terminate the lists. */
80d9c5f0 164 known[nlist - 1].next = NULL;
1522c368 165
1522c368 166 /* Pointer to last unique object. */
80d9c5f0 167 tail = &known[nlist - 1];
efec1d0c 168
92d6aa85
FW
169 struct scratch_buffer needed_space;
170 scratch_buffer_init (&needed_space);
02f9c6cf 171
1522c368
UD
172 /* Process each element of the search list, loading each of its
173 auxiliary objects and immediate dependencies. Auxiliary objects
174 will be added in the list before the object itself and
175 dependencies will be appended to the list as we step through it.
176 This produces a flat, ordered list that represents a
177 breadth-first search of the dependency tree.
178
179 The whole process is complicated by the fact that we better
180 should use alloca for the temporary list elements. But using
181 alloca means we cannot use recursive function calls. */
c77a4478
UD
182 errno_saved = errno;
183 errno_reason = 0;
184 errno = 0;
185 name = NULL;
1522c368 186 for (runp = known; runp; )
efec1d0c 187 {
1522c368 188 struct link_map *l = runp->map;
dacc8ffa
UD
189 struct link_map **needed = NULL;
190 unsigned int nneeded = 0;
191
192 /* Unless otherwise stated, this object is handled. */
193 runp->done = 1;
194
195 /* Allocate a temporary record to contain the references to the
196 dependencies of this object. */
07a3d63e
UD
197 if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
198 && l != map && l->l_ldnum > 0)
02f9c6cf 199 {
92d6aa85
FW
200 /* l->l_ldnum includes space for the terminating NULL. */
201 if (!scratch_buffer_set_array_size
202 (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
203 _dl_signal_error (ENOMEM, map->l_name, NULL,
204 N_("cannot allocate dependency buffer"));
205 needed = needed_space.data;
02f9c6cf 206 }
f68b86cc 207
8193034b 208 if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
efec1d0c 209 {
a42195db 210 const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
1522c368
UD
211 struct openaux_args args;
212 struct list *orig;
266180eb 213 const ElfW(Dyn) *d;
1522c368 214
1522c368
UD
215 args.strtab = strtab;
216 args.map = l;
217 args.trace_mode = trace_mode;
87837aac 218 args.open_mode = open_mode;
1522c368
UD
219 orig = runp;
220
efec1d0c 221 for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
e3e35cfc 222 if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
efec1d0c 223 {
f68b86cc 224 /* Map in the needed object. */
dc5efe83 225 struct link_map *dep;
dc5efe83
UD
226
227 /* Recognize DSTs. */
228 name = expand_dst (l, strtab + d->d_un.d_val, 0);
c77a4478
UD
229 /* Store the tag in the argument structure. */
230 args.name = name;
dc5efe83 231
2449ae7b
FW
232 int err = _dl_catch_exception (&exception, openaux, &args);
233 if (__glibc_unlikely (exception.errstring != NULL))
c77a4478 234 {
505d4b24
UD
235 if (err)
236 errno_reason = err;
c77a4478
UD
237 else
238 errno_reason = -1;
239 goto out;
240 }
241 else
242 dep = args.aux;
1522c368 243
42c4f32a 244 if (! dep->l_reserved)
efec1d0c 245 {
80d9c5f0
UD
246 /* Allocate new entry. */
247 struct list *newp;
248
249 newp = alloca (sizeof (struct list));
250
251 /* Append DEP to the list. */
252 newp->map = dep;
1522c368 253 newp->done = 0;
80d9c5f0
UD
254 newp->next = NULL;
255 tail->next = newp;
256 tail = newp;
f68b86cc 257 ++nlist;
f9496a7b
RM
258 /* Set the mark bit that says it's already in the list. */
259 dep->l_reserved = 1;
efec1d0c 260 }
dacc8ffa
UD
261
262 /* Remember this dependency. */
263 if (needed != NULL)
264 needed[nneeded++] = dep;
1522c368 265 }
f41c8091 266 else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
1522c368 267 {
f41c8091 268 struct list *newp;
dc5efe83
UD
269
270 /* Recognize DSTs. */
271 name = expand_dst (l, strtab + d->d_un.d_val,
272 d->d_tag == DT_AUXILIARY);
c77a4478
UD
273 /* Store the tag in the argument structure. */
274 args.name = name;
84384f5b 275
3dfb9a5c
OB
276 /* Say that we are about to load an auxiliary library. */
277 if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS,
278 0))
279 _dl_debug_printf ("load auxiliary object=%s"
280 " requested by file=%s\n",
281 name,
282 DSO_FILENAME (l->l_name));
283
284 /* We must be prepared that the addressed shared
285 object is not available. For filter objects the dependency
286 must be available. */
2449ae7b
FW
287 int err = _dl_catch_exception (&exception, openaux, &args);
288 if (__glibc_unlikely (exception.errstring != NULL))
1522c368 289 {
3dfb9a5c 290 if (d->d_tag == DT_AUXILIARY)
f41c8091
UD
291 {
292 /* We are not interested in the error message. */
2449ae7b 293 _dl_exception_free (&exception);
f41c8091
UD
294 /* Simply ignore this error and continue the work. */
295 continue;
296 }
3dfb9a5c 297 else
c77a4478 298 {
505d4b24
UD
299 if (err)
300 errno_reason = err;
c77a4478
UD
301 else
302 errno_reason = -1;
303 goto out;
304 }
8d9618b7 305 }
f41c8091
UD
306
307 /* The auxiliary object is actually available.
308 Incorporate the map in all the lists. */
309
310 /* Allocate new entry. This always has to be done. */
311 newp = alloca (sizeof (struct list));
312
ee0f7bd6
UD
313 /* We want to insert the new map before the current one,
314 but we have no back links. So we copy the contents of
315 the current entry over. Note that ORIG and NEWP now
316 have switched their meanings. */
80d9c5f0 317 memcpy (newp, orig, sizeof (*newp));
f41c8091
UD
318
319 /* Initialize new entry. */
320 orig->done = 0;
321 orig->map = args.aux;
f41c8091 322
dacc8ffa
UD
323 /* Remember this dependency. */
324 if (needed != NULL)
325 needed[nneeded++] = args.aux;
326
f41c8091
UD
327 /* We must handle two situations here: the map is new,
328 so we must add it in all three lists. If the map
329 is already known, we have two further possibilities:
330 - if the object is before the current map in the
331 search list, we do nothing. It is already found
332 early
333 - if the object is after the current one, we must
334 move it just before the current map to make sure
335 the symbols are found early enough
336 */
337 if (args.aux->l_reserved)
1522c368 338 {
f41c8091
UD
339 /* The object is already somewhere in the list.
340 Locate it first. */
341 struct list *late;
342
343 /* This object is already in the search list we
344 are building. Don't add a duplicate pointer.
42c4f32a 345 Just added by _dl_map_object. */
23382b36 346 for (late = newp; late->next != NULL; late = late->next)
80d9c5f0 347 if (late->next->map == args.aux)
f41c8091
UD
348 break;
349
23382b36 350 if (late->next != NULL)
1522c368 351 {
f41c8091
UD
352 /* The object is somewhere behind the current
353 position in the search path. We have to
354 move it to this earlier position. */
80d9c5f0 355 orig->next = newp;
f41c8091 356
80d9c5f0 357 /* Now remove the later entry from the list
ee0f7bd6 358 and adjust the tail pointer. */
80d9c5f0
UD
359 if (tail == late->next)
360 tail = late;
361 late->next = late->next->next;
f41c8091 362
ee0f7bd6 363 /* We must move the object earlier in the chain. */
23382b36 364 if (args.aux->l_prev != NULL)
1522c368 365 args.aux->l_prev->l_next = args.aux->l_next;
23382b36 366 if (args.aux->l_next != NULL)
1522c368
UD
367 args.aux->l_next->l_prev = args.aux->l_prev;
368
369 args.aux->l_prev = newp->map->l_prev;
370 newp->map->l_prev = args.aux;
371 if (args.aux->l_prev != NULL)
372 args.aux->l_prev->l_next = args.aux;
373 args.aux->l_next = newp->map;
374 }
f41c8091
UD
375 else
376 {
377 /* The object must be somewhere earlier in the
23382b36
UD
378 list. Undo to the current list element what
379 we did above. */
380 memcpy (orig, newp, sizeof (*newp));
381 continue;
f41c8091
UD
382 }
383 }
384 else
385 {
386 /* This is easy. We just add the symbol right here. */
80d9c5f0 387 orig->next = newp;
f41c8091
UD
388 ++nlist;
389 /* Set the mark bit that says it's already in the list. */
390 args.aux->l_reserved = 1;
391
392 /* The only problem is that in the double linked
393 list of all objects we don't have this new
394 object at the correct place. Correct this here. */
395 if (args.aux->l_prev)
396 args.aux->l_prev->l_next = args.aux->l_next;
397 if (args.aux->l_next)
398 args.aux->l_next->l_prev = args.aux->l_prev;
399
400 args.aux->l_prev = newp->map->l_prev;
401 newp->map->l_prev = args.aux;
402 if (args.aux->l_prev != NULL)
403 args.aux->l_prev->l_next = args.aux;
404 args.aux->l_next = newp->map;
405 }
1522c368 406
80d9c5f0
UD
407 /* Move the tail pointer if necessary. */
408 if (orig == tail)
409 tail = newp;
1522c368 410
f41c8091
UD
411 /* Move on the insert point. */
412 orig = newp;
efec1d0c
RM
413 }
414 }
dacc8ffa
UD
415
416 /* Terminate the list of dependencies and store the array address. */
417 if (needed != NULL)
418 {
419 needed[nneeded++] = NULL;
420
385b4cf4 421 struct link_map **l_initfini = (struct link_map **)
aff4519d 422 malloc ((2 * nneeded + 1) * sizeof needed[0]);
385b4cf4 423 if (l_initfini == NULL)
92d6aa85
FW
424 {
425 scratch_buffer_free (&needed_space);
426 _dl_signal_error (ENOMEM, map->l_name, NULL,
427 N_("cannot allocate dependency list"));
428 }
385b4cf4
UD
429 l_initfini[0] = l;
430 memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
431 memcpy (&l_initfini[nneeded + 1], l_initfini,
aff4519d 432 nneeded * sizeof needed[0]);
385b4cf4
UD
433 atomic_write_barrier ();
434 l->l_initfini = l_initfini;
0479b305 435 l->l_free_initfini = 1;
dacc8ffa 436 }
1522c368
UD
437
438 /* If we have no auxiliary objects just go on to the next map. */
439 if (runp->done)
440 do
80d9c5f0 441 runp = runp->next;
8193034b 442 while (runp != NULL && runp->done);
efec1d0c
RM
443 }
444
c4bb124a 445 out:
92d6aa85
FW
446 scratch_buffer_free (&needed_space);
447
c77a4478
UD
448 if (errno == 0 && errno_saved != 0)
449 __set_errno (errno_saved);
450
385b4cf4 451 struct link_map **old_l_initfini = NULL;
752a2a50
UD
452 if (map->l_initfini != NULL && map->l_type == lt_loaded)
453 {
454 /* This object was previously loaded as a dependency and we have
455 a separate l_initfini list. We don't need it anymore. */
456 assert (map->l_searchlist.r_list == NULL);
385b4cf4 457 old_l_initfini = map->l_initfini;
752a2a50
UD
458 }
459
f68b86cc
RM
460 /* Store the search list we built in the object. It will be used for
461 searches in the scope of this object. */
385b4cf4 462 struct link_map **l_initfini =
80d9c5f0 463 (struct link_map **) malloc ((2 * nlist + 1)
2e93b4a4 464 * sizeof (struct link_map *));
385b4cf4 465 if (l_initfini == NULL)
154d10bd
UD
466 _dl_signal_error (ENOMEM, map->l_name, NULL,
467 N_("cannot allocate symbol search list"));
2e93b4a4
UD
468
469
385b4cf4 470 map->l_searchlist.r_list = &l_initfini[nlist + 1];
be935610 471 map->l_searchlist.r_nlist = nlist;
eb447b7b 472 unsigned int map_index = UINT_MAX;
f68b86cc 473
80d9c5f0 474 for (nlist = 0, runp = known; runp; runp = runp->next)
f68b86cc 475 {
3a0588ae
AZ
476 /* _dl_sort_maps ignores l_faked object, so it is safe to not consider
477 them for nlist. */
c4bb124a 478 if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
ad9570d7
UD
479 /* This can happen when we trace the loading. */
480 --map->l_searchlist.r_nlist;
fbaf0bae
AZ
481 else
482 {
483 if (runp->map == map)
484 map_index = nlist;
485 map->l_searchlist.r_list[nlist++] = runp->map;
486 }
f68b86cc
RM
487
488 /* Now clear all the mark bits we set in the objects on the search list
489 to avoid duplicates, so the next call starts fresh. */
1522c368 490 runp->map->l_reserved = 0;
f68b86cc 491 }
84384f5b 492
c4bb124a 493 /* Maybe we can remove some relocation dependencies now. */
385b4cf4
UD
494 struct link_map_reldeps *l_reldeps = NULL;
495 if (map->l_reldeps != NULL)
c4bb124a 496 {
eb447b7b 497 for (i = 0; i < nlist; ++i)
385b4cf4 498 map->l_searchlist.r_list[i]->l_reserved = 1;
c4bb124a 499
eb447b7b
DK
500 /* Avoid removing relocation dependencies of the main binary. */
501 map->l_reserved = 0;
385b4cf4
UD
502 struct link_map **list = &map->l_reldeps->list[0];
503 for (i = 0; i < map->l_reldeps->act; ++i)
504 if (list[i]->l_reserved)
c4bb124a 505 {
385b4cf4 506 /* Need to allocate new array of relocation dependencies. */
385b4cf4 507 l_reldeps = malloc (sizeof (*l_reldeps)
968dad0a 508 + map->l_reldepsmax
385b4cf4
UD
509 * sizeof (struct link_map *));
510 if (l_reldeps == NULL)
511 /* Bad luck, keep the reldeps duplicated between
512 map->l_reldeps->list and map->l_initfini lists. */
513 ;
514 else
515 {
516 unsigned int j = i;
517 memcpy (&l_reldeps->list[0], &list[0],
518 i * sizeof (struct link_map *));
519 for (i = i + 1; i < map->l_reldeps->act; ++i)
520 if (!list[i]->l_reserved)
521 l_reldeps->list[j++] = list[i];
522 l_reldeps->act = j;
523 }
c4bb124a 524 }
385b4cf4 525
eb447b7b 526 for (i = 0; i < nlist; ++i)
385b4cf4 527 map->l_searchlist.r_list[i]->l_reserved = 0;
c4bb124a
UD
528 }
529
eb447b7b
DK
530 /* Sort the initializer list to take dependencies into account. Always
531 initialize the binary itself last. */
532 assert (map_index < nlist);
533 if (map_index > 0)
534 {
535 /* Copy the binary into position 0. */
536 l_initfini[0] = map->l_searchlist.r_list[map_index];
537
538 /* Copy the filtees. */
539 for (i = 0; i < map_index; ++i)
540 l_initfini[i+1] = map->l_searchlist.r_list[i];
541
542 /* Copy the remainder. */
543 for (i = map_index + 1; i < nlist; ++i)
544 l_initfini[i] = map->l_searchlist.r_list[i];
545 }
546 else
547 memcpy (l_initfini, map->l_searchlist.r_list,
548 nlist * sizeof (struct link_map *));
549
9ffa50b2
FW
550 /* If libc.so.6 is the main map, it participates in the sort, so
551 that the relocation order is correct regarding libc.so.6. */
15a0c573
CLT
552 _dl_sort_maps (l_initfini, nlist,
553 (l_initfini[0] != GL (dl_ns)[l_initfini[0]->l_ns].libc_map),
554 false);
968dad0a 555
a8571d37 556 /* Terminate the list of dependencies. */
385b4cf4
UD
557 l_initfini[nlist] = NULL;
558 atomic_write_barrier ();
559 map->l_initfini = l_initfini;
0479b305 560 map->l_free_initfini = 1;
385b4cf4
UD
561 if (l_reldeps != NULL)
562 {
563 atomic_write_barrier ();
564 void *old_l_reldeps = map->l_reldeps;
565 map->l_reldeps = l_reldeps;
566 _dl_scope_free (old_l_reldeps);
567 }
568 if (old_l_initfini != NULL)
0479b305 569 _dl_scope_free (old_l_initfini);
f55ffe58
AS
570
571 if (errno_reason)
2449ae7b
FW
572 _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
573 &exception, NULL);
efec1d0c 574}
This page took 0.667298 seconds and 6 git commands to generate.