1 /* Load the dependencies of a mapped object.
2    Copyright (C) 1996-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 #include <atomic.h>
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <errno.h>
23 #include <libintl.h>
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/param.h>
29 #include <ldsodefs.h>
30 #include <scratch_buffer.h>
31 
32 #include <dl-dst.h>
33 
34 /* Whether an shared object references one or more auxiliary objects
35    is signaled by the AUXTAG entry in l_info.  */
36 #define AUXTAG	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
37 		 + DT_EXTRATAGIDX (DT_AUXILIARY))
38 /* Whether an shared object references one or more auxiliary objects
39    is signaled by the AUXTAG entry in l_info.  */
40 #define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
41 		   + DT_EXTRATAGIDX (DT_FILTER))
42 
43 
44 /* When loading auxiliary objects we must ignore errors.  It's ok if
45    an object is missing.  */
46 struct openaux_args
47   {
48     /* The arguments to openaux.  */
49     struct link_map *map;
50     int trace_mode;
51     int open_mode;
52     const char *strtab;
53     const char *name;
54 
55     /* The return value of openaux.  */
56     struct link_map *aux;
57   };
58 
59 static void
openaux(void * a)60 openaux (void *a)
61 {
62   struct openaux_args *args = (struct openaux_args *) a;
63 
64   args->aux = _dl_map_object (args->map, args->name,
65 			      (args->map->l_type == lt_executable
66 			       ? lt_library : args->map->l_type),
67 			      args->trace_mode, args->open_mode,
68 			      args->map->l_ns);
69 }
70 
71 /* We use a very special kind of list to track the path
72    through the list of loaded shared objects.  We have to
73    produce a flat list with unique members of all involved objects.
74 */
75 struct list
76   {
77     int done;			/* Nonzero if this map was processed.  */
78     struct link_map *map;	/* The data.  */
79     struct list *next;		/* Elements for normal list.  */
80   };
81 
82 
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;					      \
88     size_t __dst_cnt = _dl_dst_count (__str);				      \
89 									      \
90     if (__dst_cnt != 0)							      \
91       {									      \
92 	char *__newp;							      \
93 									      \
94 	/* DST must not appear in SUID/SGID programs.  */		      \
95 	if (__libc_enable_secure)					      \
96 	  _dl_signal_error (0, __str, NULL, N_("\
97 DST not allowed in SUID/SGID programs"));				      \
98 									      \
99 	__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str),  \
100 						   __dst_cnt));		      \
101 									      \
102 	__result = _dl_dst_substitute (l, __str, __newp);		      \
103 									      \
104 	if (*__result == '\0')						      \
105 	  {								      \
106 	    /* The replacement for the DST is not known.  We can't	      \
107 	       processed.  */						      \
108 	    if (fatal)							      \
109 	      _dl_signal_error (0, __str, NULL, N_("\
110 empty dynamic string token substitution"));				      \
111 	    else							      \
112 	      {								      \
113 		/* This is for DT_AUXILIARY.  */			      \
114 		if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))   \
115 		  _dl_debug_printf (N_("\
116 cannot load auxiliary `%s' because of empty dynamic string token "	      \
117 					    "substitution\n"), __str);	      \
118 		continue;						      \
119 	      }								      \
120 	  }								      \
121       }									      \
122 									      \
123     __result; })
124 
125 static void
preload(struct list * known,unsigned int * nlist,struct link_map * map)126 preload (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 }
138 
139 void
_dl_map_object_deps(struct link_map * map,struct link_map ** preloads,unsigned int npreloads,int trace_mode,int open_mode)140 _dl_map_object_deps (struct link_map *map,
141 		     struct link_map **preloads, unsigned int npreloads,
142 		     int trace_mode, int open_mode)
143 {
144   struct list *known = __alloca (sizeof *known * (1 + npreloads + 1));
145   struct list *runp, *tail;
146   unsigned int nlist, i;
147   /* Object name.  */
148   const char *name;
149   int errno_saved;
150   int errno_reason;
151   struct dl_exception exception;
152 
153   /* No loaded object so far.  */
154   nlist = 0;
155 
156   /* First load MAP itself.  */
157   preload (known, &nlist, map);
158 
159   /* Add the preloaded items after MAP but before any of its dependencies.  */
160   for (i = 0; i < npreloads; ++i)
161     preload (known, &nlist, preloads[i]);
162 
163   /* Terminate the lists.  */
164   known[nlist - 1].next = NULL;
165 
166   /* Pointer to last unique object.  */
167   tail = &known[nlist - 1];
168 
169   struct scratch_buffer needed_space;
170   scratch_buffer_init (&needed_space);
171 
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.  */
182   errno_saved = errno;
183   errno_reason = 0;
184   errno = 0;
185   name = NULL;
186   for (runp = known; runp; )
187     {
188       struct link_map *l = runp->map;
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.  */
197       if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
198 	  && l != map && l->l_ldnum > 0)
199 	{
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;
206 	}
207 
208       if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
209 	{
210 	  const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
211 	  struct openaux_args args;
212 	  struct list *orig;
213 	  const ElfW(Dyn) *d;
214 
215 	  args.strtab = strtab;
216 	  args.map = l;
217 	  args.trace_mode = trace_mode;
218 	  args.open_mode = open_mode;
219 	  orig = runp;
220 
221 	  for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
222 	    if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
223 	      {
224 		/* Map in the needed object.  */
225 		struct link_map *dep;
226 
227 		/* Recognize DSTs.  */
228 		name = expand_dst (l, strtab + d->d_un.d_val, 0);
229 		/* Store the tag in the argument structure.  */
230 		args.name = name;
231 
232 		int err = _dl_catch_exception (&exception, openaux, &args);
233 		if (__glibc_unlikely (exception.errstring != NULL))
234 		  {
235 		    if (err)
236 		      errno_reason = err;
237 		    else
238 		      errno_reason = -1;
239 		    goto out;
240 		  }
241 		else
242 		  dep = args.aux;
243 
244 		if (! dep->l_reserved)
245 		  {
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;
253 		    newp->done = 0;
254 		    newp->next = NULL;
255 		    tail->next = newp;
256 		    tail = newp;
257 		    ++nlist;
258 		    /* Set the mark bit that says it's already in the list.  */
259 		    dep->l_reserved = 1;
260 		  }
261 
262 		/* Remember this dependency.  */
263 		if (needed != NULL)
264 		  needed[nneeded++] = dep;
265 	      }
266 	    else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER)
267 	      {
268 		struct list *newp;
269 
270 		/* Recognize DSTs.  */
271 		name = expand_dst (l, strtab + d->d_un.d_val,
272 				   d->d_tag == DT_AUXILIARY);
273 		/* Store the tag in the argument structure.  */
274 		args.name = name;
275 
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.  */
287 		int err = _dl_catch_exception (&exception, openaux, &args);
288 		if (__glibc_unlikely (exception.errstring != NULL))
289 		  {
290 		    if (d->d_tag == DT_AUXILIARY)
291 		      {
292 			/* We are not interested in the error message.  */
293 			_dl_exception_free (&exception);
294 			/* Simply ignore this error and continue the work.  */
295 			continue;
296 		      }
297 		    else
298 		      {
299 			if (err)
300 			  errno_reason = err;
301 			else
302 			  errno_reason = -1;
303 			goto out;
304 		      }
305 		  }
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 
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.  */
317 		memcpy (newp, orig, sizeof (*newp));
318 
319 		/* Initialize new entry.  */
320 		orig->done = 0;
321 		orig->map = args.aux;
322 
323 		/* Remember this dependency.  */
324 		if (needed != NULL)
325 		  needed[nneeded++] = args.aux;
326 
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)
338 		  {
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.
345 		       Just added by _dl_map_object.  */
346 		    for (late = newp; late->next != NULL; late = late->next)
347 		      if (late->next->map == args.aux)
348 			break;
349 
350 		    if (late->next != NULL)
351 		      {
352 			/* The object is somewhere behind the current
353 			   position in the search path.  We have to
354 			   move it to this earlier position.  */
355 			orig->next = newp;
356 
357 			/* Now remove the later entry from the list
358 			   and adjust the tail pointer.  */
359 			if (tail == late->next)
360 			  tail = late;
361 			late->next = late->next->next;
362 
363 			/* We must move the object earlier in the chain.  */
364 			if (args.aux->l_prev != NULL)
365 			  args.aux->l_prev->l_next = args.aux->l_next;
366 			if (args.aux->l_next != NULL)
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 		      }
375 		    else
376 		      {
377 			/* The object must be somewhere earlier in the
378 			   list.  Undo to the current list element what
379 			   we did above.  */
380 			memcpy (orig, newp, sizeof (*newp));
381 			continue;
382 		      }
383 		  }
384 		else
385 		  {
386 		    /* This is easy.  We just add the symbol right here.  */
387 		    orig->next = newp;
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 		  }
406 
407 		/* Move the tail pointer if necessary.  */
408 		if (orig == tail)
409 		  tail = newp;
410 
411 		/* Move on the insert point.  */
412 		orig = newp;
413 	      }
414 	}
415 
416       /* Terminate the list of dependencies and store the array address.  */
417       if (needed != NULL)
418 	{
419 	  needed[nneeded++] = NULL;
420 
421 	  struct link_map **l_initfini = (struct link_map **)
422 	    malloc ((2 * nneeded + 1) * sizeof needed[0]);
423 	  if (l_initfini == NULL)
424 	    {
425 	      scratch_buffer_free (&needed_space);
426 	      _dl_signal_error (ENOMEM, map->l_name, NULL,
427 				N_("cannot allocate dependency list"));
428 	    }
429 	  l_initfini[0] = l;
430 	  memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
431 	  memcpy (&l_initfini[nneeded + 1], l_initfini,
432 		  nneeded * sizeof needed[0]);
433 	  atomic_write_barrier ();
434 	  l->l_initfini = l_initfini;
435 	  l->l_free_initfini = 1;
436 	}
437 
438       /* If we have no auxiliary objects just go on to the next map.  */
439       if (runp->done)
440 	do
441 	  runp = runp->next;
442 	while (runp != NULL && runp->done);
443     }
444 
445  out:
446   scratch_buffer_free (&needed_space);
447 
448   if (errno == 0 && errno_saved != 0)
449     __set_errno (errno_saved);
450 
451   struct link_map **old_l_initfini = NULL;
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);
457       old_l_initfini = map->l_initfini;
458     }
459 
460   /* Store the search list we built in the object.  It will be used for
461      searches in the scope of this object.  */
462   struct link_map **l_initfini =
463     (struct link_map **) malloc ((2 * nlist + 1)
464 				 * sizeof (struct link_map *));
465   if (l_initfini == NULL)
466     _dl_signal_error (ENOMEM, map->l_name, NULL,
467 		      N_("cannot allocate symbol search list"));
468 
469 
470   map->l_searchlist.r_list = &l_initfini[nlist + 1];
471   map->l_searchlist.r_nlist = nlist;
472   unsigned int map_index = UINT_MAX;
473 
474   for (nlist = 0, runp = known; runp; runp = runp->next)
475     {
476       /* _dl_sort_maps ignores l_faked object, so it is safe to not consider
477 	 them for nlist.  */
478       if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
479 	/* This can happen when we trace the loading.  */
480 	--map->l_searchlist.r_nlist;
481       else
482 	{
483 	  if (runp->map == map)
484 	    map_index = nlist;
485 	  map->l_searchlist.r_list[nlist++] = runp->map;
486 	}
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.  */
490       runp->map->l_reserved = 0;
491     }
492 
493   /* Maybe we can remove some relocation dependencies now.  */
494   struct link_map_reldeps *l_reldeps = NULL;
495   if (map->l_reldeps != NULL)
496     {
497       for (i = 0; i < nlist; ++i)
498 	map->l_searchlist.r_list[i]->l_reserved = 1;
499 
500       /* Avoid removing relocation dependencies of the main binary.  */
501       map->l_reserved = 0;
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)
505 	  {
506 	    /* Need to allocate new array of relocation dependencies.  */
507 	    l_reldeps = malloc (sizeof (*l_reldeps)
508 				+ map->l_reldepsmax
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 	      }
524 	  }
525 
526       for (i = 0; i < nlist; ++i)
527 	map->l_searchlist.r_list[i]->l_reserved = 0;
528     }
529 
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 
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.  */
552   _dl_sort_maps (l_initfini, nlist,
553 		 (l_initfini[0] != GL (dl_ns)[l_initfini[0]->l_ns].libc_map),
554 		 false);
555 
556   /* Terminate the list of dependencies.  */
557   l_initfini[nlist] = NULL;
558   atomic_write_barrier ();
559   map->l_initfini = l_initfini;
560   map->l_free_initfini = 1;
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)
569     _dl_scope_free (old_l_initfini);
570 
571   if (errno_reason)
572     _dl_signal_exception (errno_reason == -1 ? 0 : errno_reason,
573 			  &exception, NULL);
574 }
575