]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/dl-load.c
Update copyright notices with scripts/update-copyrights
[thirdparty/glibc.git] / elf / dl-load.c
index 0b896d9b47ac58bc86b23629a48e0ef7b92841cb..434dcb88632609989f20fde1f6cbee156399d6b3 100644 (file)
@@ -1,5 +1,5 @@
 /* Map in a shared object's segments from the file.
-   Copyright (C) 1995-2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1995-2014 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -13,9 +13,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <elf.h>
 #include <errno.h>
@@ -36,6 +35,7 @@
 #include <stackinfo.h>
 #include <caller.h>
 #include <sysdep.h>
+#include <stap-probe.h>
 
 #include <dl-dst.h>
 
@@ -168,6 +168,87 @@ local_strdup (const char *s)
 }
 
 
+static bool
+is_trusted_path (const char *path, size_t len)
+{
+  const char *trun = system_dirs;
+
+  for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
+    {
+      if (len == system_dirs_len[idx] && memcmp (trun, path, len) == 0)
+       /* Found it.  */
+       return true;
+
+      trun += system_dirs_len[idx] + 1;
+    }
+
+  return false;
+}
+
+
+static bool
+is_trusted_path_normalize (const char *path, size_t len)
+{
+  if (len == 0)
+    return false;
+
+  if (*path == ':')
+    {
+      ++path;
+      --len;
+    }
+
+  char *npath = (char *) alloca (len + 2);
+  char *wnp = npath;
+  while (*path != '\0')
+    {
+      if (path[0] == '/')
+       {
+         if (path[1] == '.')
+           {
+             if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
+               {
+                 while (wnp > npath && *--wnp != '/')
+                   ;
+                 path += 3;
+                 continue;
+               }
+             else if (path[2] == '/' || path[2] == '\0')
+               {
+                 path += 2;
+                 continue;
+               }
+           }
+
+         if (wnp > npath && wnp[-1] == '/')
+           {
+             ++path;
+             continue;
+           }
+       }
+
+      *wnp++ = *path++;
+    }
+
+  if (wnp == npath || wnp[-1] != '/')
+    *wnp++ = '/';
+
+  const char *trun = system_dirs;
+
+  for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
+    {
+      if (wnp - npath >= system_dirs_len[idx]
+         && memcmp (trun, npath, system_dirs_len[idx]) == 0)
+       /* Found it.  */
+       return true;
+
+      trun += system_dirs_len[idx] + 1;
+    }
+
+  return false;
+}
+
+
 static size_t
 is_dst (const char *start, const char *name, const char *str,
        int is_path, int secure)
@@ -200,7 +281,8 @@ is_dst (const char *start, const char *name, const char *str,
     return 0;
 
   if (__builtin_expect (secure, 0)
-      && ((name[len] != '\0' && (!is_path || name[len] != ':'))
+      && ((name[len] != '\0' && name[len] != '/'
+          && (!is_path || name[len] != ':'))
          || (name != start + 1 && (!is_path || name[-2] != ':'))))
     return 0;
 
@@ -240,13 +322,14 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
                    int is_path)
 {
   const char *const start = name;
-  char *last_elem, *wp;
 
   /* Now fill the result path.  While copying over the string we keep
-     track of the start of the last path element.  When we come accross
+     track of the start of the last path element.  When we come across
      a DST we copy over the value or (if the value is not available)
      leave the entire path element out.  */
-  last_elem = wp = result;
+  char *wp = result;
+  char *last_elem = result;
+  bool check_for_trusted = false;
 
   do
     {
@@ -259,12 +342,9 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
          if ((len = is_dst (start, name, "ORIGIN", is_path,
                             INTUSE(__libc_enable_secure))) != 0)
            {
-#ifndef SHARED
-             if (l == NULL)
-               repl = _dl_get_origin ();
-             else
-#endif
-               repl = l->l_origin;
+             repl = l->l_origin;
+             check_for_trusted = (INTUSE(__libc_enable_secure)
+                                  && l->l_type == lt_executable);
            }
          else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
            repl = GLRO(dl_platform);
@@ -284,6 +364,10 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
              name += len;
              while (*name != '\0' && (!is_path || *name != ':'))
                ++name;
+             /* Also skip following colon if this is the first rpath
+                element, but keep an empty element at the end.  */
+             if (wp == result && is_path && *name == ':' && name[1] != '\0')
+               ++name;
            }
          else
            /* No DST we recognize.  */
@@ -293,11 +377,28 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
        {
          *wp++ = *name++;
          if (is_path && *name == ':')
-           last_elem = wp;
+           {
+             /* In SUID/SGID programs, after $ORIGIN expansion the
+                normalized path must be rooted in one of the trusted
+                directories.  */
+             if (__builtin_expect (check_for_trusted, false)
+                 && !is_trusted_path_normalize (last_elem, wp - last_elem))
+               wp = last_elem;
+             else
+               last_elem = wp;
+
+             check_for_trusted = false;
+           }
        }
     }
   while (*name != '\0');
 
+  /* In SUID/SGID programs, after $ORIGIN expansion the normalized
+     path must be rooted in one of the trusted directories.  */
+  if (__builtin_expect (check_for_trusted, false)
+      && !is_trusted_path_normalize (last_elem, wp - last_elem))
+    wp = last_elem;
+
   *wp = '\0';
 
   return result;
@@ -310,10 +411,10 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
    belonging to the map is loaded.  In this case the path element
    containing $ORIGIN is left out.  */
 static char *
-expand_dynamic_string_token (struct link_map *l, const char *s)
+expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
 {
   /* We make two runs over the string.  First we determine how large the
-     resulting string is and then we copy it over.  Since this is now
+     resulting string is and then we copy it over.  Since this is no
      frequently executed operation we are looking here not for performance
      but rather for code size.  */
   size_t cnt;
@@ -321,7 +422,7 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
   char *result;
 
   /* Determine the number of DST elements.  */
-  cnt = DL_DST_COUNT (s, 1);
+  cnt = DL_DST_COUNT (s, is_path);
 
   /* If we do not have to replace anything simply copy the string.  */
   if (__builtin_expect (cnt, 0) == 0)
@@ -335,7 +436,7 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
   if (result == NULL)
     return NULL;
 
-  return _dl_dst_substitute (l, s, result, 1);
+  return _dl_dst_substitute (l, s, result, is_path);
 }
 
 
@@ -380,18 +481,23 @@ static size_t max_dirnamelen;
 
 static struct r_search_path_elem **
 fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
-             int check_trusted, const char *what, const char *where)
+             int check_trusted, const char *what, const char *where,
+             struct link_map *l)
 {
   char *cp;
   size_t nelems = 0;
+  char *to_free;
 
   while ((cp = __strsep (&rpath, sep)) != NULL)
     {
       struct r_search_path_elem *dirp;
+
+      to_free = cp = expand_dynamic_string_token (l, cp, 1);
+
       size_t len = strlen (cp);
 
       /* `strsep' can pass an empty string.  This has to be
-         interpreted as `use the current directory'. */
+        interpreted as `use the current directory'. */
       if (len == 0)
        {
          static const char curwd[] = "./";
@@ -407,32 +513,10 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
        cp[len++] = '/';
 
       /* Make sure we don't use untrusted directories if we run SUID.  */
-      if (__builtin_expect (check_trusted, 0))
+      if (__builtin_expect (check_trusted, 0) && !is_trusted_path (cp, len))
        {
-         const char *trun = system_dirs;
-         size_t idx;
-         int unsecure = 1;
-
-         /* All trusted directories must be complete names.  */
-         if (cp[0] == '/')
-           {
-             for (idx = 0; idx < nsystem_dirs_len; ++idx)
-               {
-                 if (len == system_dirs_len[idx]
-                     && memcmp (trun, cp, len) == 0)
-                   {
-                     /* Found it.  */
-                     unsecure = 0;
-                     break;
-                   }
-
-                 trun += system_dirs_len[idx] + 1;
-               }
-           }
-
-         if (unsecure)
-           /* Simply drop this directory.  */
-           continue;
+         free (to_free);
+         continue;
        }
 
       /* See if this directory is already known.  */
@@ -494,6 +578,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
          /* Put it in the result array.  */
          result[nelems++] = dirp;
        }
+      free (to_free);
     }
 
   /* Terminate the array.  */
@@ -549,15 +634,22 @@ decompose_rpath (struct r_search_path_struct *sps,
       while (*inhp != '\0');
     }
 
-  /* Make a writable copy.  At the same time expand possible dynamic
-     string tokens.  */
-  copy = expand_dynamic_string_token (l, rpath);
+  /* Make a writable copy.  */
+  copy = local_strdup (rpath);
   if (copy == NULL)
     {
       errstring = N_("cannot create RUNPATH/RPATH copy");
       goto signal_error;
     }
 
+  /* Ignore empty rpaths.  */
+  if (*copy == 0)
+    {
+      free (copy);
+      sps->dirs = (struct r_search_path_elem **) -1;
+      return false;
+    }
+
   /* Count the number of necessary elements in the result array.  */
   nelems = 0;
   for (cp = copy; *cp != '\0'; ++cp)
@@ -576,7 +668,7 @@ decompose_rpath (struct r_search_path_struct *sps,
       _dl_signal_error (ENOMEM, NULL, NULL, errstring);
     }
 
-  fillin_rpath (copy, result, ":", 0, what, where);
+  fillin_rpath (copy, result, ":", 0, what, where, l);
 
   /* Free the copied RPATH string.  `fillin_rpath' make own copies if
      necessary.  */
@@ -624,9 +716,7 @@ _dl_init_paths (const char *llp)
   const char *strp;
   struct r_search_path_elem *pelem, **aelem;
   size_t round_size;
-#ifdef SHARED
-  struct link_map *l;
-#endif
+  struct link_map __attribute__ ((unused)) *l = NULL;
   /* Initialize to please the compiler.  */
   const char *errstring = NULL;
 
@@ -707,6 +797,9 @@ _dl_init_paths (const char *llp)
                           (const void *) (D_PTR (l, l_info[DT_STRTAB])
                                           + l->l_info[DT_RUNPATH]->d_un.d_val),
                           l, "RUNPATH");
+         /* During rtld init the memory is allocated by the stub malloc,
+            prevent any attempt to free it by the normal malloc.  */
+         l->l_runpath_dirs.malloced = 0;
 
          /* The RPATH is ignored.  */
          l->l_rpath_dirs.dirs = (void *) -1;
@@ -723,6 +816,9 @@ _dl_init_paths (const char *llp)
                               (const void *) (D_PTR (l, l_info[DT_STRTAB])
                                               + l->l_info[DT_RPATH]->d_un.d_val),
                               l, "RPATH");
+             /* During rtld init the memory is allocated by the stub
+                malloc, prevent any attempt to free it by the normal
+                malloc.  */
              l->l_rpath_dirs.malloced = 0;
            }
          else
@@ -775,7 +871,7 @@ _dl_init_paths (const char *llp)
 
       (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
                           INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH",
-                          NULL);
+                          NULL, l);
 
       if (env_path_list.dirs[0] == NULL)
        {
@@ -787,39 +883,27 @@ _dl_init_paths (const char *llp)
     }
   else
     env_path_list.dirs = (void *) -1;
-
-  /* Remember the last search directory added at startup.  */
-  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
 }
 
 
 static void
 __attribute__ ((noreturn, noinline))
 lose (int code, int fd, const char *name, char *realname, struct link_map *l,
-      const char *msg, struct r_debug *r)
+      const char *msg, struct r_debug *r, Lmid_t nsid)
 {
   /* The file might already be closed.  */
   if (fd != -1)
     (void) __close (fd);
-  if (l != NULL)
-    {
-      /* Remove the stillborn object from the list and free it.  */
-      assert (l->l_next == NULL);
-      if (l->l_prev == NULL)
-       /* No other module loaded. This happens only in the static library,
-          or in rtld under --verify.  */
-       GL(dl_ns)[l->l_ns]._ns_loaded = NULL;
-      else
-       l->l_prev->l_next = NULL;
-      --GL(dl_ns)[l->l_ns]._ns_nloaded;
-      free (l);
-    }
+  if (l != NULL && l->l_origin != (char *) -1l)
+    free ((char *) l->l_origin);
+  free (l);
   free (realname);
 
   if (r != NULL)
     {
       r->r_state = RT_CONSISTENT;
       _dl_debug_state ();
+      LIBC_PROBE (map_failed, 2, nsid, r);
     }
 
   _dl_signal_error (code, name, NULL, msg);
@@ -858,7 +942,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
       errval = errno;
     call_lose:
       lose (errval, fd, name, realname, l, errstring,
-           make_consistent ? r : NULL);
+           make_consistent ? r : NULL, nsid);
     }
 
   /* Look again to see if the real name matched another already loaded.  */
@@ -898,14 +982,21 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
         never be unloaded.  */
       __close (fd);
 
+      /* Add the map for the mirrored object to the object list.  */
+      _dl_add_to_namespace_list (l, nsid);
+
       return l;
     }
 #endif
 
   if (mode & RTLD_NOLOAD)
-    /* We are not supposed to load the object unless it is already
-       loaded.  So return now.  */
-    return NULL;
+    {
+      /* We are not supposed to load the object unless it is already
+        loaded.  So return now.  */
+      free (realname);
+      __close (fd);
+      return NULL;
+    }
 
   /* Print debugging message.  */
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
@@ -921,6 +1012,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
       if (_dl_zerofd == -1)
        {
+         free (realname);
          __close (fd);
          _dl_signal_error (errno, NULL, NULL,
                            N_("cannot open zero fill device"));
@@ -957,6 +1049,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
         linking has not been used before.  */
       r->r_state = RT_ADD;
       _dl_debug_state ();
+      LIBC_PROBE (map_start, 2, nsid, r);
       make_consistent = true;
     }
   else
@@ -993,15 +1086,17 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
        }
     }
 
-  /* Presumed absent PT_GNU_STACK.  */
-  uint_fast16_t stack_flags = PF_R|PF_W|PF_X;
+   /* On most platforms presume that PT_GNU_STACK is absent and the stack is
+    * executable.  Other platforms default to a nonexecutable stack and don't
+    * need PT_GNU_STACK to do so.  */
+   uint_fast16_t stack_flags = DEFAULT_STACK_PERMS;
 
   {
     /* Scan the program header table, collecting its load commands.  */
     struct loadcmd
       {
        ElfW(Addr) mapstart, mapend, dataend, allocend;
-       off_t mapoff;
+       ElfW(Off) mapoff;
        int prot;
       } loadcmds[l->l_phnum], *c;
     size_t nloadcmds = 0;
@@ -1105,9 +1200,11 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
               was executed directly.  The setup will happen later.  */
            break;
 
+# ifdef _LIBC_REENTRANT
          /* In a static binary there is no way to tell if we dynamically
             loaded libpthread.  */
          if (GL(dl_error_catch_tsd) == &_dl_initial_error_catch_tsd)
+# endif
 #endif
            {
              /* We have not yet loaded libpthread.
@@ -1256,11 +1353,12 @@ cannot allocate TLS data structures for initial thread");
          l->l_text_end = l->l_addr + c->mapend;
 
        if (l->l_phdr == 0
-           && (ElfW(Off)) c->mapoff <= header->e_phoff
+           && c->mapoff <= header->e_phoff
            && ((size_t) (c->mapend - c->mapstart + c->mapoff)
                >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr))))
          /* Found the program header in this segment.  */
-         l->l_phdr = (void *) (c->mapstart + header->e_phoff - c->mapoff);
+         l->l_phdr = (void *) (uintptr_t) (c->mapstart + header->e_phoff
+                                           - c->mapoff);
 
        if (c->allocend > c->dataend)
          {
@@ -1395,7 +1493,11 @@ cannot allocate TLS data structures for initial thread");
          if (__builtin_expect (p + s <= relro_end, 1))
            {
              /* The variable lies in the region protected by RELRO.  */
-             __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
+             if (__mprotect ((void *) p, s, PROT_READ|PROT_WRITE) < 0)
+               {
+                 errstring = N_("cannot change memory protections");
+                 goto call_lose_errno;
+               }
              __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
              __mprotect ((void *) p, s, PROT_READ);
            }
@@ -1489,6 +1591,13 @@ cannot enable executable stack as shared object requires");
     add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
                            + l->l_info[DT_SONAME]->d_un.d_val));
 
+#ifdef DL_AFTER_LOAD
+  DL_AFTER_LOAD (l);
+#endif
+
+  /* Now that the object is fully initialized add it to the object list.  */
+  _dl_add_to_namespace_list (l, nsid);
+
 #ifdef SHARED
   /* Auditing checkpoint: we have a new object.  */
   if (__builtin_expect (GLRO(dl_naudit) > 0, 0)
@@ -1516,7 +1625,7 @@ cannot enable executable stack as shared object requires");
 /* Print search path.  */
 static void
 print_search_path (struct r_search_path_elem **list,
-                   const char *what, const char *name)
+                  const char *what, const char *name)
 {
   char buf[max_dirnamelen + max_capstrlen];
   int first = 1;
@@ -1546,7 +1655,7 @@ print_search_path (struct r_search_path_elem **list,
 
   if (name != NULL)
     _dl_debug_printf_c ("\t\t(%s from file %s)\n", what,
-                       name[0] ? name : rtld_progname);
+                       DSO_FILENAME (name));
   else
     _dl_debug_printf_c ("\t\t(%s)\n", what);
 }
@@ -1566,11 +1675,11 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 #ifndef VALID_ELF_HEADER
 # define VALID_ELF_HEADER(hdr,exp,size)        (memcmp (hdr, exp, size) == 0)
 # define VALID_ELF_OSABI(osabi)                (osabi == ELFOSABI_SYSV)
-# define VALID_ELF_ABIVERSION(ver)     (ver == 0)
+# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0)
 #elif defined MORE_ELF_HEADER_DATA
   MORE_ELF_HEADER_DATA;
 #endif
-  static const unsigned char expected[EI_PAD] =
+  static const unsigned char expected[EI_NIDENT] =
   {
     [EI_MAG0] = ELFMAG0,
     [EI_MAG1] = ELFMAG1,
@@ -1616,7 +1725,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 #endif
 
   /* Open the file.  We always open files read-only.  */
-  int fd = __open (name, O_RDONLY);
+  int fd = __open (name, O_RDONLY | O_CLOEXEC);
   if (fd != -1)
     {
       ElfW(Ehdr) *ehdr;
@@ -1628,10 +1737,20 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
       /* We successfully openened the file.  Now verify it is a file
         we can use.  */
       __set_errno (0);
-      fbp->len = __libc_read (fd, fbp->buf, sizeof (fbp->buf));
+      fbp->len = 0;
+      assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
+      /* Read in the header.  */
+      do
+        {
+          ssize_t retlen = __libc_read (fd, fbp->buf + fbp->len,
+                                       sizeof (fbp->buf) - fbp->len);
+         if (retlen <= 0)
+           break;
+         fbp->len += retlen;
+       }
+      while (__builtin_expect (fbp->len < sizeof (ElfW(Ehdr)), 0));
 
       /* This is where the ELF header is loaded.  */
-      assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
       ehdr = (ElfW(Ehdr) *) fbp->buf;
 
       /* Now run the tests.  */
@@ -1647,12 +1766,18 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
              name = strdupa (realname);
              free (realname);
            }
-         lose (errval, fd, name, NULL, NULL, errstring, NULL);
+         lose (errval, fd, name, NULL, NULL, errstring, NULL, 0);
        }
 
       /* See whether the ELF header is what we expect.  */
       if (__builtin_expect (! VALID_ELF_HEADER (ehdr->e_ident, expected,
-                                               EI_PAD), 0))
+                                               EI_ABIVERSION)
+                           || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
+                                                     ehdr->e_ident[EI_ABIVERSION])
+                           || memcmp (&ehdr->e_ident[EI_PAD],
+                                      &expected[EI_PAD],
+                                      EI_NIDENT - EI_PAD) != 0,
+                           0))
        {
          /* Something is wrong.  */
          const Elf32_Word *magp = (const void *) ehdr->e_ident;
@@ -1692,8 +1817,12 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
             allowed here.  */
          else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI]))
            errstring = N_("ELF file OS ABI invalid");
-         else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_ABIVERSION]))
+         else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
+                                         ehdr->e_ident[EI_ABIVERSION]))
            errstring = N_("ELF file ABI version invalid");
+         else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD],
+                          EI_NIDENT - EI_PAD) != 0)
+           errstring = N_("nonzero padding in e_ident");
          else
            /* Otherwise we don't know what went wrong.  */
            errstring = N_("internal error");
@@ -1799,7 +1928,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
    if MAY_FREE_DIRS is true.  */
 
 static int
-open_path (const char *name, size_t namelen, int preloaded,
+open_path (const char *name, size_t namelen, int secure,
           struct r_search_path_struct *sps, char **realname,
           struct filebuf *fbp, struct link_map *loader, int whatcode,
           bool *found_other_class)
@@ -1881,7 +2010,7 @@ open_path (const char *name, size_t namelen, int preloaded,
          /* Remember whether we found any existing directory.  */
          here_any |= this_dir->status[cnt] != nonexisting;
 
-         if (fd != -1 && __builtin_expect (preloaded, 0)
+         if (fd != -1 && __builtin_expect (secure, 0)
              && INTUSE(__libc_enable_secure))
            {
              /* This is an extra security effort to make sure nobody can
@@ -1950,7 +2079,7 @@ open_path (const char *name, size_t namelen, int preloaded,
 
 struct link_map *
 internal_function
-_dl_map_object (struct link_map *loader, const char *name, int preloaded,
+_dl_map_object (struct link_map *loader, const char *name,
                int type, int trace_mode, int mode, Lmid_t nsid)
 {
   int fd;
@@ -1996,9 +2125,10 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
   /* Display information if we are debugging.  */
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
       && loader != NULL)
-    _dl_debug_printf ("\nfile=%s [%lu];  needed by %s [%lu]\n", name, nsid,
-                             loader->l_name[0]
-                             ? loader->l_name : rtld_progname, loader->l_ns);
+    _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
+                     ? "\nfile=%s [%lu];  needed by %s [%lu]\n"
+                     : "\nfile=%s [%lu];  dynamically loaded by %s [%lu]\n",
+                     name, nsid, DSO_FILENAME (loader->l_name), loader->l_ns);
 
 #ifdef SHARED
   /* Give the auditing libraries a chance to change the name before we
@@ -2041,7 +2171,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       fd = -1;
 
       /* When the object has the RUNPATH information we don't use any
-         RPATHs.  */
+        RPATHs.  */
       if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL)
        {
          /* This is the executable's map (if there is one).  Make sure that
@@ -2054,7 +2184,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
          for (l = loader; l; l = l->l_loader)
            if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
              {
-               fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
+               fd = open_path (name, namelen, mode & __RTLD_SECURE,
+                               &l->l_rpath_dirs,
                                &realname, &fb, loader, LA_SER_RUNPATH,
                                &found_other_class);
                if (fd != -1)
@@ -2064,19 +2195,20 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
              }
 
          /* If dynamically linked, try the DT_RPATH of the executable
-             itself.  NB: we do this for lookups in any namespace.  */
+            itself.  NB: we do this for lookups in any namespace.  */
          if (fd == -1 && !did_main_map
              && main_map != NULL && main_map->l_type != lt_loaded
              && cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
                              "RPATH"))
-           fd = open_path (name, namelen, preloaded, &main_map->l_rpath_dirs,
+           fd = open_path (name, namelen, mode & __RTLD_SECURE,
+                           &main_map->l_rpath_dirs,
                            &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
                            &found_other_class);
        }
 
       /* Try the LD_LIBRARY_PATH environment variable.  */
       if (fd == -1 && env_path_list.dirs != (void *) -1)
-       fd = open_path (name, namelen, preloaded, &env_path_list,
+       fd = open_path (name, namelen, mode & __RTLD_SECURE, &env_path_list,
                        &realname, &fb,
                        loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
                        LA_SER_LIBPATH, &found_other_class);
@@ -2085,13 +2217,15 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       if (fd == -1 && loader != NULL
          && cache_rpath (loader, &loader->l_runpath_dirs,
                          DT_RUNPATH, "RUNPATH"))
-       fd = open_path (name, namelen, preloaded,
+       fd = open_path (name, namelen, mode & __RTLD_SECURE,
                        &loader->l_runpath_dirs, &realname, &fb, loader,
                        LA_SER_RUNPATH, &found_other_class);
 
+#ifdef USE_LDCONFIG
       if (fd == -1
-         && (__builtin_expect (! preloaded, 1)
-             || ! INTUSE(__libc_enable_secure)))
+         && (__builtin_expect (! (mode & __RTLD_SECURE), 1)
+             || ! INTUSE(__libc_enable_secure))
+         && __builtin_expect (GLRO(dl_inhibit_cache) == 0, 1))
        {
          /* Check the list of libraries in the file /etc/ld.so.cache,
             for compatibility with Linux's ldconfig program.  */
@@ -2099,20 +2233,22 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
          if (cached != NULL)
            {
-#ifdef SHARED
+# ifdef SHARED
              // XXX Correct to unconditionally default to namespace 0?
-             l = loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-#else
+             l = (loader
+                  ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded
+                  ?: &GL(dl_rtld_map));
+# else
              l = loader;
-#endif
+# endif
 
              /* If the loader has the DF_1_NODEFLIB flag set we must not
                 use a cache entry from any of these directories.  */
              if (
-#ifndef SHARED
+# ifndef SHARED
                  /* 'l' is always != NULL for dynamically linked objects.  */
                  l != NULL &&
-#endif
+# endif
                  __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0))
                {
                  const char *dirp = system_dirs;
@@ -2150,24 +2286,25 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
                }
            }
        }
+#endif
 
       /* Finally, try the default path.  */
       if (fd == -1
          && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
              || __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
          && rtld_search_dirs.dirs != (void *) -1)
-       fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
+       fd = open_path (name, namelen, mode & __RTLD_SECURE, &rtld_search_dirs,
                        &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
 
       /* Add another newline when we are tracing the library loading.  */
       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
-        _dl_debug_printf ("\n");
+       _dl_debug_printf ("\n");
     }
   else
     {
       /* The path may contain dynamic string tokens.  */
       realname = (loader
-                 ? expand_dynamic_string_token (loader, name)
+                 ? expand_dynamic_string_token (loader, name, 0)
                  : local_strdup (name));
       if (realname == NULL)
        fd = -1;
@@ -2201,7 +2338,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
             have.  */
          static const Elf_Symndx dummy_bucket = STN_UNDEF;
 
-         /* Enter the new object in the list of loaded objects.  */
+         /* Allocate a new object map.  */
          if ((name_copy = local_strdup (name)) == NULL
              || (l = _dl_new_object (name_copy, name, type, loader,
                                      mode, nsid)) == NULL)
@@ -2219,6 +2356,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
          l->l_nbuckets = 1;
          l->l_relocated = 1;
 
+         /* Enter the object in the object list.  */
+         _dl_add_to_namespace_list (l, nsid);
+
          return l;
        }
       else if (found_other_class)