summary refs log tree commit diff
path: root/elf/dl-deps.c
diff options
context:
space:
mode:
authorDavid Kilroy <David.Kilroy@arm.com>2020-02-12 14:28:15 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-02-12 14:29:48 -0300
commiteb447b7b4bd6177f876ba9420ad9e048c27bae91 (patch)
treecbde7ab262bfc6b74c6b4a7f9eb1984fdb3e6485 /elf/dl-deps.c
parent6721b9d52e3bdc7cbec97e6b2952c523c14aebee (diff)
downloadglibc-eb447b7b4bd6177f876ba9420ad9e048c27bae91.tar.gz
glibc-eb447b7b4bd6177f876ba9420ad9e048c27bae91.tar.xz
glibc-eb447b7b4bd6177f876ba9420ad9e048c27bae91.zip
elf: Allow dlopen of filter object to work [BZ #16272]
There are two fixes that are needed to be able to dlopen filter
objects. First _dl_map_object_deps cannot assume that map will be at
the beginning of l_searchlist.r_list[], as filtees are inserted before
map. Secondly dl_open_worker needs to ensure that filtees get
relocated.

In _dl_map_object_deps:

* avoiding removing relocation dependencies of map by setting
  l_reserved to 0 and otherwise processing the rest of the search
  list.

* ensure that map remains at the beginning of l_initfini - the list
  of things that need initialisation (and destruction). Do this by
  splitting the copy up. This may not be required, but matches the
  initialization order without dlopen.

Modify dl_open_worker to relocate the objects in new->l_inifini.
new->l_initfini is constructed in _dl_map_object_deps, and lists the
objects that need initialization and destruction. Originally the list
of objects in new->l_next are relocated. All of these objects should
also be included in new->l_initfini (both lists are populated with
dependencies in _dl_map_object_deps). We can't use new->l_prev to pick
up filtees, as during a recursive dlopen from an interposed malloc
call, l->prev can contain objects that are not ready for relocation.

Add tests to verify that symbols resolve to the filtee implementation
when auxiliary and filter objects are used, both as a normal link and
when dlopen'd.

Tested by running the testsuite on x86_64.
Diffstat (limited to 'elf/dl-deps.c')
-rw-r--r--elf/dl-deps.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 5103a8a111..0730ea9bd1 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -485,14 +485,18 @@ _dl_map_object_deps (struct link_map *map,
 
   map->l_searchlist.r_list = &l_initfini[nlist + 1];
   map->l_searchlist.r_nlist = nlist;
+  unsigned int map_index = UINT_MAX;
 
   for (nlist = 0, runp = known; runp; runp = runp->next)
     {
       if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
 	/* This can happen when we trace the loading.  */
 	--map->l_searchlist.r_nlist;
-      else
+      else {
+	if (runp->map == map)
+	  map_index = nlist;
 	map->l_searchlist.r_list[nlist++] = runp->map;
+      }
 
       /* Now clear all the mark bits we set in the objects on the search list
 	 to avoid duplicates, so the next call starts fresh.  */
@@ -550,13 +554,14 @@ Filters not supported with LD_TRACE_PRELINKING"));
     }
 
   /* Maybe we can remove some relocation dependencies now.  */
-  assert (map->l_searchlist.r_list[0] == map);
   struct link_map_reldeps *l_reldeps = NULL;
   if (map->l_reldeps != NULL)
     {
-      for (i = 1; i < nlist; ++i)
+      for (i = 0; i < nlist; ++i)
 	map->l_searchlist.r_list[i]->l_reserved = 1;
 
+      /* Avoid removing relocation dependencies of the main binary.  */
+      map->l_reserved = 0;
       struct link_map **list = &map->l_reldeps->list[0];
       for (i = 0; i < map->l_reldeps->act; ++i)
 	if (list[i]->l_reserved)
@@ -581,16 +586,30 @@ Filters not supported with LD_TRACE_PRELINKING"));
 	      }
 	  }
 
-      for (i = 1; i < nlist; ++i)
+      for (i = 0; i < nlist; ++i)
 	map->l_searchlist.r_list[i]->l_reserved = 0;
     }
 
-  /* Sort the initializer list to take dependencies into account.  The binary
-     itself will always be initialize last.  */
-  memcpy (l_initfini, map->l_searchlist.r_list,
-	  nlist * sizeof (struct link_map *));
-  /* We can skip looking for the binary itself which is at the front of
-     the search list.  */
+  /* Sort the initializer list to take dependencies into account.  Always
+     initialize the binary itself last.  */
+  assert (map_index < nlist);
+  if (map_index > 0)
+    {
+      /* Copy the binary into position 0.  */
+      l_initfini[0] = map->l_searchlist.r_list[map_index];
+
+      /* Copy the filtees.  */
+      for (i = 0; i < map_index; ++i)
+	l_initfini[i+1] = map->l_searchlist.r_list[i];
+
+      /* Copy the remainder.  */
+      for (i = map_index + 1; i < nlist; ++i)
+	l_initfini[i] = map->l_searchlist.r_list[i];
+    }
+  else
+    memcpy (l_initfini, map->l_searchlist.r_list,
+	    nlist * sizeof (struct link_map *));
+
   _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
 
   /* Terminate the list of dependencies.  */