about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-deps.c23
-rw-r--r--elf/dl-fini.c6
-rw-r--r--elf/dl-load.c12
-rw-r--r--elf/dl-minimal.c11
-rw-r--r--elf/dl-open.c2
-rw-r--r--elf/dl-runtime.c2
-rw-r--r--elf/link.h10
-rw-r--r--elf/rtld.c47
8 files changed, 93 insertions, 20 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 9fe974d982..28733ab60d 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -23,20 +23,29 @@ Cambridge, MA 02139, USA.  */
 #include <stdlib.h>
 
 void
-_dl_map_object_deps (struct link_map *map)
+_dl_map_object_deps (struct link_map *map,
+		     struct link_map **preloads, unsigned int npreloads)
 {
   struct list
     {
       struct link_map *map;
       struct list *next;
     };
-  struct list head, *tailp, *scanp;
+  struct list head[1 + npreloads], *tailp, *scanp;
   unsigned int nlist;
 
   /* Start the search list with one element: MAP itself.  */
-  head.map = map;
-  head.next = NULL;
-  nlist = 1;
+  head[0].map = map;
+
+  /* Add the preloaded items after MAP but before any of its dependencies.  */
+  for (nlist = 0; nlist < npreloads; ++nlist)
+    {
+      head[nlist].next = &head[nlist + 1];
+      head[nlist + 1].map = preloads[nlist];
+    }
+
+  /* Terminate the list.  */
+  head[nlist++].next = NULL;
 
   /* We use `l_reserved' as a mark bit to detect objects we have already
      put in the search list and avoid adding duplicate elements later in
@@ -47,7 +56,7 @@ _dl_map_object_deps (struct link_map *map)
      dependencies and appending them to the list as we step through it.
      This produces a flat, ordered list that represents a breadth-first
      search of the dependency tree.  */
-  for (scanp = tailp = &head; scanp; scanp = scanp->next)
+  for (scanp = tailp = head; scanp; scanp = scanp->next)
     {
       struct link_map *l = scanp->map;
 
@@ -91,7 +100,7 @@ _dl_map_object_deps (struct link_map *map)
   map->l_nsearchlist = nlist;
 
   nlist = 0;
-  for (scanp = &head; scanp; scanp = scanp->next)
+  for (scanp = head; scanp; scanp = scanp->next)
     {
       map->l_searchlist[nlist++] = scanp->map;
 
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 36b4390663..9f4233aca0 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -25,9 +25,11 @@ _dl_fini (void)
   struct link_map *l;
 
   for (l = _dl_loaded; l; l = l->l_next)
-    if (l->l_init_called && l->l_info[DT_FINI])
+    if (l->l_init_called)
       {
-	(*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
+	if (l->l_info[DT_FINI] &&
+	    !(l->l_name[0] == '\0' && l->l_type == lt_executable))
+	  (*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
 	/* Make sure nothing happens if we are called twice.  */
 	l->l_init_called = 0;
       }
diff --git a/elf/dl-load.c b/elf/dl-load.c
index ff7f5cf487..29ac0bfd87 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -59,7 +59,14 @@ Cambridge, MA 02139, USA.  */
 
 #define STRING(x) #x
 
+#ifdef MAP_ANON
+/* The fd is not examined when using MAP_ANON.  */
+#define ANONFD -1
+#else
 int _dl_zerofd = -1;
+#define ANONFD _dl_zerofd
+#endif
+
 size_t _dl_pagesize;
 
 
@@ -176,6 +183,8 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
   if (header->e_phentsize != sizeof (ElfW(Phdr)))
     LOSE ("ELF file's phentsize not the expected size");
 
+#ifndef MAP_ANON
+#define MAP_ANON 0
   if (_dl_zerofd == -1)
     {
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
@@ -185,6 +194,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
 	  _dl_signal_error (errno, NULL, "cannot open zero fill device");
 	}
     }
+#endif
 
   /* Enter the new object in the list of loaded objects.  */
   l = _dl_new_object (realname, name, l_type);
@@ -329,7 +339,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
 		caddr_t mapat;
 		mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
 				c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
-				_dl_zerofd, 0);
+				ANONFD, 0);
 		if (mapat == (caddr_t) -1)
 		  lose (errno, "cannot map zero-fill pages");
 	      }
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index fd7bf05497..61615cd9a9 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -33,13 +33,18 @@ static void *alloc_ptr, *alloc_end, *alloc_last_block;
 void * weak_function
 malloc (size_t n)
 {
+#ifdef MAP_ANON
+#define	_dl_zerofd (-1)
+#else
   extern int _dl_zerofd;
 
-  if (_dl_pagesize == 0)
-    _dl_pagesize = __getpagesize ();
-
   if (_dl_zerofd == -1)
     _dl_zerofd = _dl_sysdep_open_zero_fill ();
+#define MAP_ANON 0
+#endif
+
+  if (_dl_pagesize == 0)
+    _dl_pagesize = __getpagesize ();
 
   if (alloc_end == 0)
     {
diff --git a/elf/dl-open.c b/elf/dl-open.c
index c24920f933..058c3e5a39 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -39,7 +39,7 @@ _dl_open (const char *file, int mode)
     return new;
 
   /* Load that object's dependencies.  */
-  _dl_map_object_deps (new);
+  _dl_map_object_deps (new, NULL, 0);
 
 
   /* Relocate the objects loaded.  We do this in reverse order so that copy
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 8ad2c0ffa4..cdacd756ef 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -41,7 +41,7 @@ _dl_object_relocation_scope (struct link_map *l)
 
       if (! l->l_searchlist)
 	/* We must construct the searchlist for this object.  */
-	_dl_map_object_deps (l);
+	_dl_map_object_deps (l, NULL, 0);
 
       /* The primary scope is this object itself and its
 	 dependencies.  */
diff --git a/elf/link.h b/elf/link.h
index 1e0104a4ea..fa96613478 100644
--- a/elf/link.h
+++ b/elf/link.h
@@ -196,9 +196,13 @@ extern int _dlerror_run (void (*operate) (void));
 extern struct link_map *_dl_map_object (struct link_map *loader,
 					const char *name, int type);
 
-/* Call _dl_map_object on the dependencies of MAP, and
-   set up MAP->l_searchlist.  */
-extern void _dl_map_object_deps (struct link_map *map);
+/* Call _dl_map_object on the dependencies of MAP, and set up
+   MAP->l_searchlist.  PRELOADS points to a vector of NPRELOADS previously
+   loaded objects that will be inserted into MAP->l_searchlist after MAP
+   but before its dependencies.  */
+extern void _dl_map_object_deps (struct link_map *map,
+				 struct link_map **preloads,
+				 unsigned int npreloads);
 
 /* Cache the locations of MAP's hash table.  */
 extern void _dl_setup_hash (struct link_map *map);
diff --git a/elf/rtld.c b/elf/rtld.c
index 6baa7a868a..2e23d9cb38 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -21,6 +21,7 @@ Cambridge, MA 02139, USA.  */
 #include <stddef.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <sys/mman.h>		/* Check if MAP_ANON is defined.  */
 #include "../stdio-common/_itoa.h"
 
 
@@ -124,6 +125,8 @@ dl_main (const ElfW(Phdr) *phdr,
   struct link_map *l;
   int lazy;
   int list_only = 0;
+  struct link_map **preloads;
+  unsigned int npreloads;
 
   if (*user_entry == (ElfW(Addr)) &_start)
     {
@@ -247,12 +250,52 @@ of this helper program; chances are you did not intend to run this program.\n",
   l->l_next = &_dl_rtld_map;
   _dl_rtld_map.l_prev = l;
 
-  /* Load all the libraries specified by DT_NEEDED entries.  */
-  _dl_map_object_deps (l);
+  preloads = NULL;
+  npreloads = 0;
+  if (! _dl_secure)
+    {
+      const char *preloadlist = getenv ("LD_PRELOAD");
+      if (preloadlist)
+	{
+	  /* The LD_PRELOAD environment variable gives a colon-separated
+	     list of libraries that are loaded before the executable's
+	     dependencies and prepended to the global scope list.  */
+	  char *list = strdupa (preloadlist);
+	  char *p;
+	  while ((p = strsep (&list, ":")) != NULL)
+	    {
+	      (void) _dl_map_object (NULL, p, lt_library);
+	      ++npreloads;
+	    }
+
+	  if (npreloads != 0)
+	    {
+	      /* Set up PRELOADS with a vector of the preloaded libraries.  */
+	      struct link_map *l;
+	      unsigned int i;
+	      preloads = __alloca (npreloads * sizeof preloads[0]);
+	      l = _dl_rtld_map.l_next; /* End of the chain before preloads.  */
+	      i = 0;
+	      do
+		{
+		  preloads[i++] = l;
+		  l = l->l_next;
+		} while (l);
+	      assert (i == npreloads);
+	    }
+	}
+    }
+
+  /* Load all the libraries specified by DT_NEEDED entries.  If LD_PRELOAD
+     specified some libraries to load, these are inserted before the actual
+     dependencies in the executable's searchlist for symbol resolution.  */
+  _dl_map_object_deps (l, preloads, npreloads);
 
+#ifndef MAP_ANON
   /* We are done mapping things, so close the zero-fill descriptor.  */
   __close (_dl_zerofd);
   _dl_zerofd = -1;
+#endif
 
   /* Remove _dl_rtld_map from the chain.  */
   _dl_rtld_map.l_prev->l_next = _dl_rtld_map.l_next;