]> sourceware.org Git - glibc.git/blobdiff - elf/rtld.c
handle password file locking.
[glibc.git] / elf / rtld.c
index 6dc68226db56269194af1c69236f1fa3e799b996..be71e88c3cf6cab1a4eb401684f4d8c7253d9fd7 100644 (file)
@@ -18,47 +18,62 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
 #include <link.h>
-#include "dynamic-link.h"
 #include <stddef.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
+#include <sys/mman.h>          /* Check if MAP_ANON is defined.  */
 #include "../stdio-common/_itoa.h"
+#include <assert.h>
+#include "dynamic-link.h"
 
 
-#ifdef RTLD_START
-RTLD_START
-#else
-#error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START"
-#endif
-
 /* System-specific function to do initial startup for the dynamic linker.
    After this, file access calls and getenv must work.  This is responsible
-   for setting _dl_secure if we need to be secure (e.g. setuid),
+   for setting __libc_enable_secure if we need to be secure (e.g. setuid),
    and for setting _dl_argc and _dl_argv, and then calling _dl_main.  */
-extern Elf32_Addr _dl_sysdep_start (void **start_argptr,
-                                   void (*dl_main) (const Elf32_Phdr *phdr,
-                                                    Elf32_Word phent,
-                                                    Elf32_Addr *user_entry));
+extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
+                                   void (*dl_main) (const ElfW(Phdr) *phdr,
+                                                    ElfW(Half) phent,
+                                                    ElfW(Addr) *user_entry));
 extern void _dl_sysdep_start_cleanup (void);
 
-int _dl_secure;
 int _dl_argc;
 char **_dl_argv;
 const char *_dl_rpath;
 
-struct r_debug dl_r_debug;
+/* Set nonzero during loading and initialization of executable and
+   libraries, cleared before the executable's entry point runs.  This
+   must not be initialized to nonzero, because the unused dynamic
+   linker loaded in for libc.so's "ld.so.1" dep will provide the
+   definition seen by libc.so's initializer; that value must be zero,
+   and will be since that dynamic linker's _dl_start and dl_main will
+   never be called.  */
+int _dl_starting_up;
 
-static void dl_main (const Elf32_Phdr *phdr,
-                    Elf32_Word phent,
-                    Elf32_Addr *user_entry);
+static void dl_main (const ElfW(Phdr) *phdr,
+                    ElfW(Half) phent,
+                    ElfW(Addr) *user_entry);
 
-static struct link_map rtld_map;
+struct link_map _dl_rtld_map;
 
-Elf32_Addr
+#ifdef RTLD_START
+RTLD_START
+#else
+#error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START"
+#endif
+
+ElfW(Addr)
 _dl_start (void *arg)
 {
   struct link_map bootstrap_map;
 
+  /* This #define produces dynamic linking inline functions for
+     bootstrap relocation instead of general-purpose relocation.  */
+#define RTLD_BOOTSTRAP
+#define RESOLVE(sym, flags) bootstrap_map.l_addr
+#include "dynamic-link.h"
+
   /* Figure out the run-time load address of the dynamic linker itself.  */
   bootstrap_map.l_addr = elf_machine_load_address ();
 
@@ -75,14 +90,7 @@ _dl_start (void *arg)
   /* Relocate ourselves so we can do normal function calls and
      data access using the global offset table.  */
 
-  /* We must initialize `l_type' to make sure it is not `lt_interpreter'.
-     That is the type to describe us, but not during bootstrapping--it
-     indicates to elf_machine_rel{,a} that we were already relocated during
-     bootstrapping, so it must anti-perform each bootstrapping relocation
-     before applying the final relocation when ld.so is linked in as
-     normal a shared library.  */
-  bootstrap_map.l_type = lt_library;
-  ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, NULL);
+  ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0);
 
 
   /* Now life is sane; we can call functions and access global data.
@@ -92,22 +100,23 @@ _dl_start (void *arg)
 
 
   /* Transfer data about ourselves to the permanent link_map structure.  */
-  rtld_map.l_addr = bootstrap_map.l_addr;
-  rtld_map.l_ld = bootstrap_map.l_ld;
-  memcpy (rtld_map.l_info, bootstrap_map.l_info, sizeof rtld_map.l_info);
-  _dl_setup_hash (&rtld_map);
+  _dl_rtld_map.l_addr = bootstrap_map.l_addr;
+  _dl_rtld_map.l_ld = bootstrap_map.l_ld;
+  memcpy (_dl_rtld_map.l_info, bootstrap_map.l_info,
+         sizeof _dl_rtld_map.l_info);
+  _dl_setup_hash (&_dl_rtld_map);
 
   /* Cache the DT_RPATH stored in ld.so itself; this will be
      the default search path.  */
-  _dl_rpath = (void *) (rtld_map.l_addr +
-                       rtld_map.l_info[DT_STRTAB]->d_un.d_ptr +
-                       rtld_map.l_info[DT_RPATH]->d_un.d_val);
+  _dl_rpath = (void *) (_dl_rtld_map.l_addr +
+                       _dl_rtld_map.l_info[DT_STRTAB]->d_un.d_ptr +
+                       _dl_rtld_map.l_info[DT_RPATH]->d_un.d_val);
 
   /* Call the OS-dependent function to set up life so we can do things like
      file access.  It will call `dl_main' (below) to do all the real work
      of the dynamic linker, and then unwind our frame and run the user
      entry point on the same stack we entered on.  */
-  return _dl_sysdep_start (&arg, &dl_main);
+  return _dl_sysdep_start (arg, &dl_main);
 }
 
 
@@ -119,17 +128,20 @@ void _start (void);
 unsigned int _dl_skip_args;    /* Nonzero if we were run directly.  */
 
 static void
-dl_main (const Elf32_Phdr *phdr,
-        Elf32_Word phent,
-        Elf32_Addr *user_entry)
+dl_main (const ElfW(Phdr) *phdr,
+        ElfW(Half) phent,
+        ElfW(Addr) *user_entry)
 {
-  const Elf32_Phdr *ph;
+  const ElfW(Phdr) *ph;
   struct link_map *l;
-  const char *interpreter_name;
   int lazy;
-  int list_only = 0;
+  enum { normal, list, verify, trace } mode;
+  struct link_map **preloads;
+  unsigned int npreloads;
+
+  mode = getenv ("LD_TRACE_LOADED_OBJECTS") != NULL ? trace : normal;
 
-  if (*user_entry == (Elf32_Addr) &_start)
+  if (*user_entry == (ElfW(Addr)) &_start)
     {
       /* Ho ho.  We are not the program interpreter!  We are the program
         itself!  This means someone ran ld.so as a command.  Well, that
@@ -148,7 +160,7 @@ dl_main (const Elf32_Phdr *phdr,
         installing it.  */
       if (_dl_argc < 2)
        _dl_sysdep_fatal ("\
-Usage: ld.so [--list] EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
+Usage: ld.so [--list|--verify] EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
 You have invoked `ld.so', the helper program for shared library executables.\n\
 This program usually lives in the file `/lib/ld.so', and special directives\n\
 in executable files using ELF shared libraries tell the system's program\n\
@@ -162,11 +174,20 @@ file you run.  This is mostly of use for maintainers to test new versions\n\
 of this helper program; chances are you did not intend to run this program.\n",
                          NULL);
 
-      interpreter_name = _dl_argv[0];
+      /* Note the place where the dynamic linker actually came from.  */
+      _dl_rtld_map.l_name = _dl_argv[0];
 
       if (! strcmp (_dl_argv[1], "--list"))
        {
-         list_only = 1;
+         mode = list;
+
+         ++_dl_skip_args;
+         --_dl_argc;
+         ++_dl_argv;
+       }
+      else if (! strcmp (_dl_argv[1], "--verify"))
+       {
+         mode = verify;
 
          ++_dl_skip_args;
          --_dl_argc;
@@ -177,7 +198,25 @@ of this helper program; chances are you did not intend to run this program.\n",
       --_dl_argc;
       ++_dl_argv;
 
-      l = _dl_map_object (NULL, _dl_argv[0]);
+      if (mode == verify)
+       {
+         void doit (void)
+           {
+             l = _dl_map_object (NULL, _dl_argv[0], lt_library);
+           }
+         char *err_str = NULL;
+         const char *obj_name __attribute__ ((unused));
+
+         (void) _dl_catch_error (&err_str, &obj_name, doit);
+         if (err_str != NULL)
+           {
+             free (err_str);
+             _exit (EXIT_FAILURE);
+           }
+       }
+      else
+       l = _dl_map_object (NULL, _dl_argv[0], lt_library);
+
       phdr = l->l_phdr;
       phent = l->l_phnum;
       l->l_name = (char *) "";
@@ -190,7 +229,6 @@ of this helper program; chances are you did not intend to run this program.\n",
       l = _dl_new_object ((char *) "", "", lt_executable);
       l->l_phdr = phdr;
       l->l_phnum = phent;
-      interpreter_name = 0;
       l->l_entry = *user_entry;
     }
 
@@ -224,10 +262,21 @@ of this helper program; chances are you did not intend to run this program.\n",
           dlopen call or DT_NEEDED entry, for something that wants to link
           against the dynamic linker as a shared library, will know that
           the shared object is already loaded.  */
-       interpreter_name = (void *) l->l_addr + ph->p_vaddr;
+       _dl_rtld_map.l_libname = (const char *) l->l_addr + ph->p_vaddr;
        break;
       }
-  assert (interpreter_name);   /* How else did we get here?  */
+  if (! _dl_rtld_map.l_libname && _dl_rtld_map.l_name)
+    /* We were invoked directly, so the program might not have a PT_INTERP.  */
+    _dl_rtld_map.l_libname = _dl_rtld_map.l_name;
+  else
+    assert (_dl_rtld_map.l_libname); /* How else did we get here?  */
+
+  if (mode == verify)
+    /* We were called just to verify that this is a dynamic executable
+       using us as the program interpreter.  */
+    _exit ((strcmp (_dl_rtld_map.l_libname, _dl_rtld_map.l_name) ||
+           l->l_ld == NULL)
+          ? EXIT_FAILURE : EXIT_SUCCESS);
 
   /* Extract the contents of the dynamic section for easy access.  */
   elf_get_dynamic_info (l->l_ld, l->l_info);
@@ -235,37 +284,92 @@ of this helper program; chances are you did not intend to run this program.\n",
     /* Set up our cache of pointers into the hash table.  */
     _dl_setup_hash (l);
 
-  if (l->l_info[DT_DEBUG])
-    /* There is a DT_DEBUG entry in the dynamic section.  Fill it in
-       with the run-time address of the r_debug structure, which we
-       will set up later to communicate with the debugger.  */
-    l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;
-
   /* Put the link_map for ourselves on the chain so it can be found by
      name.  */
-  rtld_map.l_name = (char *) rtld_map.l_libname = interpreter_name;
-  rtld_map.l_type = lt_interpreter;
+  if (! _dl_rtld_map.l_name)
+    /* If not invoked directly, the dynamic linker shared object file was
+       found by the PT_INTERP name.  */
+    _dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname;
+  _dl_rtld_map.l_type = lt_library;
   while (l->l_next)
     l = l->l_next;
-  l->l_next = &rtld_map;
-  rtld_map.l_prev = l;
+  l->l_next = &_dl_rtld_map;
+  _dl_rtld_map.l_prev = l;
+
+  preloads = NULL;
+  npreloads = 0;
+  if (! __libc_enable_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
 
-  /* Load all the libraries specified by DT_NEEDED entries.  */
-  _dl_map_object_deps (l);
+  /* Remove _dl_rtld_map from the chain.  */
+  _dl_rtld_map.l_prev->l_next = _dl_rtld_map.l_next;
+  if (_dl_rtld_map.l_next)
+    _dl_rtld_map.l_next->l_prev = _dl_rtld_map.l_prev;
 
-  /* XXX if kept, move it so l_next list is in dep order because
-     it will determine gdb's search order.
-     Perhaps do this always, so later dlopen by name finds it?
-     XXX But then gdb always considers it present.  */
-  if (rtld_map.l_opencount == 0)
+  if (_dl_rtld_map.l_opencount)
     {
-      /* No DT_NEEDED entry referred to the interpreter object itself,
-        so remove it from the list of visible objects.  */
-      rtld_map.l_prev->l_next = rtld_map.l_next;
-      rtld_map.l_next->l_prev = rtld_map.l_prev;
+      /* Some DT_NEEDED entry referred to the interpreter object itself, so
+        put it back in the list of visible objects.  We insert it into the
+        chain in symbol search order because gdb uses the chain's order as
+        its symbol search order.  */
+      unsigned int i = 1;
+      while (l->l_searchlist[i] != &_dl_rtld_map)
+       ++i;
+      _dl_rtld_map.l_prev = l->l_searchlist[i - 1];
+      _dl_rtld_map.l_next = (i + 1 < l->l_nsearchlist ?
+                            l->l_searchlist[i + 1] : NULL);
+      assert (_dl_rtld_map.l_prev->l_next == _dl_rtld_map.l_next);
+      _dl_rtld_map.l_prev->l_next = &_dl_rtld_map;
+      if (_dl_rtld_map.l_next)
+       {
+         assert (_dl_rtld_map.l_next->l_prev == _dl_rtld_map.l_prev);
+         _dl_rtld_map.l_next->l_prev = &_dl_rtld_map;
+       }
     }
 
-  if (list_only)
+  if (mode != normal)
     {
       /* We were run just to list the shared libraries.  It is
         important that we do this before real relocation, because the
@@ -288,86 +392,117 @@ of this helper program; chances are you did not intend to run this program.\n",
                                " (0x", bp, ")\n", NULL);
          }
 
-      for (i = 1; i < _dl_argc; ++i)
-       {
-         const Elf32_Sym *ref = NULL;
-         struct link_map *scope[2] ={ _dl_loaded, NULL };
-         Elf32_Addr loadbase
-           = _dl_lookup_symbol (_dl_argv[i], &ref, scope, "argument", 0, 0);
-         char buf[20], *bp;
-         buf[sizeof buf - 1] = '\0';
-         bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 0);
-         while (&buf[sizeof buf - 1] - bp < sizeof loadbase * 2)
-           *--bp = '0';
-         _dl_sysdep_message (_dl_argv[i], " found at 0x", bp, NULL);
-         buf[sizeof buf - 1] = '\0';
-         bp = _itoa (loadbase, &buf[sizeof buf - 1], 16, 0);
-         while (&buf[sizeof buf - 1] - bp < sizeof loadbase * 2)
-           *--bp = '0';
-         _dl_sysdep_message (" in object at 0x", bp, "\n", NULL);
-       }
+      if (mode != trace)
+       for (i = 1; i < _dl_argc; ++i)
+         {
+           const ElfW(Sym) *ref = NULL;
+           ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
+                                                    &_dl_default_scope[2],
+                                                    "argument",
+                                                    DL_LOOKUP_NOPLT);
+           char buf[20], *bp;
+           buf[sizeof buf - 1] = '\0';
+           bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 0);
+           while (&buf[sizeof buf - 1] - bp < sizeof loadbase * 2)
+             *--bp = '0';
+           _dl_sysdep_message (_dl_argv[i], " found at 0x", bp, NULL);
+           buf[sizeof buf - 1] = '\0';
+           bp = _itoa (loadbase, &buf[sizeof buf - 1], 16, 0);
+           while (&buf[sizeof buf - 1] - bp < sizeof loadbase * 2)
+             *--bp = '0';
+           _dl_sysdep_message (" in object at 0x", bp, "\n", NULL);
+         }
 
       _exit (0);
     }
 
-  lazy = !_dl_secure && *(getenv ("LD_BIND_NOW") ?: "") == '\0';
-
-  /* Now we have all the objects loaded.  Relocate them all except for
-     the dynamic linker itself.  We do this in reverse order so that
-     copy relocs of earlier objects overwrite the data written by later
-     objects.  We do not re-relocate the dynamic linker itself in this
-     loop because that could result in the GOT entries for functions we
-     call being changed, and that would break us.  It is safe to
-     relocate the dynamic linker out of order because it has no copy
-     relocs (we know that because it is self-contained).  */
-  l = _dl_loaded;
-  while (l->l_next)
-    l = l->l_next;
-  do
-    {
-      if (l != &rtld_map)
-       _dl_relocate_object (l, lazy);
-      l = l->l_prev;
-    } while (l);
-
-  /* Do any necessary cleanups for the startup OS interface code.
-     We do these now so that no calls are made after rtld re-relocation
-     which might be resolved to different functions than we expect.
-     We cannot do this before relocating the other objects because
-     _dl_relocate_object might need to call `mprotect' for DT_TEXTREL.  */
-  _dl_sysdep_start_cleanup ();
-
-  if (rtld_map.l_opencount > 0)
-    /* There was an explicit ref to the dynamic linker as a shared lib.
-       Re-relocate ourselves with user-controlled symbol definitions.  */
-    _dl_relocate_object (&rtld_map, lazy);
-
-  /* Tell the debugger where to find the map of loaded objects.  */
-  dl_r_debug.r_version = 1     /* R_DEBUG_VERSION XXX */;
-  dl_r_debug.r_ldbase = rtld_map.l_addr; /* Record our load address.  */
-  dl_r_debug.r_map = _dl_loaded;
-  dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
-
-  if (rtld_map.l_info[DT_INIT])
+  lazy = !__libc_enable_secure && *(getenv ("LD_BIND_NOW") ?: "") == '\0';
+
+  {
+    /* Now we have all the objects loaded.  Relocate them all except for
+       the dynamic linker itself.  We do this in reverse order so that copy
+       relocs of earlier objects overwrite the data written by later
+       objects.  We do not re-relocate the dynamic linker itself in this
+       loop because that could result in the GOT entries for functions we
+       call being changed, and that would break us.  It is safe to relocate
+       the dynamic linker out of order because it has no copy relocs (we
+       know that because it is self-contained).  */
+
+    l = _dl_loaded;
+    while (l->l_next)
+      l = l->l_next;
+    do
+      {
+       if (l != &_dl_rtld_map)
+         {
+           _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy);
+           *_dl_global_scope_end = NULL;
+         }
+       l = l->l_prev;
+      } while (l);
+
+    /* Do any necessary cleanups for the startup OS interface code.
+       We do these now so that no calls are made after rtld re-relocation
+       which might be resolved to different functions than we expect.
+       We cannot do this before relocating the other objects because
+       _dl_relocate_object might need to call `mprotect' for DT_TEXTREL.  */
+    _dl_sysdep_start_cleanup ();
+
+    if (_dl_rtld_map.l_opencount > 0)
+      /* There was an explicit ref to the dynamic linker as a shared lib.
+        Re-relocate ourselves with user-controlled symbol definitions.  */
+      _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0);
+  }
+
+  {
+    /* Initialize _r_debug.  */
+    struct r_debug *r = _dl_debug_initialize (_dl_rtld_map.l_addr);
+
+    l = _dl_loaded;
+
+#ifdef ELF_MACHINE_DEBUG_SETUP
+
+    /* Some machines (e.g. MIPS) don't use DT_DEBUG in this way.  */
+
+    ELF_MACHINE_DEBUG_SETUP (l, r);
+    ELF_MACHINE_DEBUG_SETUP (&_dl_rtld_map, r);
+
+#else
+
+    if (l->l_info[DT_DEBUG])
+      /* There is a DT_DEBUG entry in the dynamic section.  Fill it in
+        with the run-time address of the r_debug structure  */
+      l->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
+
+    /* Fill in the pointer in the dynamic linker's own dynamic section, in
+       case you run gdb on the dynamic linker directly.  */
+    if (_dl_rtld_map.l_info[DT_DEBUG])
+      _dl_rtld_map.l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
+
+#endif
+
+    /* Notify the debugger that all objects are now mapped in.  */
+    r->r_state = RT_ADD;
+    _dl_debug_state ();
+  }
+
+  if (_dl_rtld_map.l_info[DT_INIT])
     {
       /* Call the initializer for the compatibility version of the
         dynamic linker.  There is no additional initialization
         required for the ABI-compliant dynamic linker.  */
 
-      (*(void (*) (void)) (rtld_map.l_addr +
-                          rtld_map.l_info[DT_INIT]->d_un.d_ptr)) ();
+      (*(void (*) (int, char **, char**))
+       (_dl_rtld_map.l_addr + _dl_rtld_map.l_info[DT_INIT]->d_un.d_ptr))
+       (0, NULL, NULL);
 
       /* Clear the field so a future dlopen won't run it again.  */
-      rtld_map.l_info[DT_INIT] = NULL;
+      _dl_rtld_map.l_info[DT_INIT] = NULL;
     }
 
+  /* We finished the intialization and will start up.  */
+  _dl_starting_up = 1;
+
   /* Once we return, _dl_sysdep_start will invoke
      the DT_INIT functions and then *USER_ENTRY.  */
 }
-
-/* This function exists solely to have a breakpoint set on it by the
-   debugger.  */
-void
-_dl_r_debug_state (void)
-{
-}
This page took 0.038283 seconds and 5 git commands to generate.