summaryrefslogtreecommitdiff
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;