]> 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 0d3fbb425bcea9c1548835a0722ea21c0fae43c7..434dcb88632609989f20fde1f6cbee156399d6b3 100644 (file)
@@ -1,5 +1,5 @@
 /* Map in a shared object's segments from the file.
-   Copyright (C) 1995-2002, 2003, 2004, 2005 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>
 
    overwritten.  Some losing VM systems like Linux's lack MAP_COPY.  All we
    get is MAP_PRIVATE, which copies each page when it is modified; this
    means if the file is overwritten, we may at some point get some pages
-   from the new version after starting with pages from the old version.  */
+   from the new version after starting with pages from the old version.
+
+   To make up for the lack and avoid the overwriting problem,
+   what Linux does have is MAP_DENYWRITE.  This prevents anyone
+   from modifying the file while we have it mapped.  */
 #ifndef MAP_COPY
-# define MAP_COPY      MAP_PRIVATE
+# ifdef MAP_DENYWRITE
+#  define MAP_COPY     (MAP_PRIVATE | MAP_DENYWRITE)
+# else
+#  define MAP_COPY     MAP_PRIVATE
+# endif
 #endif
 
 /* Some systems link their relocatable objects for another base address
 
 #define STRING(x) __STRING (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
-
 /* Handle situations where we have a preferred location in memory for
    the shared objects.  */
 #ifdef ELF_PREFERRED_ADDRESS_DATA
@@ -116,19 +116,19 @@ int __stack_prot attribute_hidden attribute_relro
    question is how large are the ELF and program header combined.  The
    ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
    bytes long.  Each program header entry is again 32 and 56 bytes
-   long respectively.  I.e., even with a file which has 7 program
-   header entries we only have to read 512B.  Add to this a bit of
-   margin for program notes and reading 512B and 640B for 32-bit and
-   64-bit files respecitvely is enough.  If this heuristic should
-   really fail for some file the code in `_dl_map_object_from_fd'
-   knows how to recover.  */
+   long respectively.  I.e., even with a file which has 10 program
+   header entries we only have to read 372B/624B respectively.  Add to
+   this a bit of margin for program notes and reading 512B and 832B
+   for 32-bit and 64-bit files respecitvely is enough.  If this
+   heuristic should really fail for some file the code in
+   `_dl_map_object_from_fd' knows how to recover.  */
 struct filebuf
 {
   ssize_t len;
 #if __WORDSIZE == 32
 # define FILEBUF_SIZE 512
 #else
-# define FILEBUF_SIZE 640
+# define FILEBUF_SIZE 832
 #endif
   char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
 };
@@ -155,7 +155,7 @@ static const size_t system_dirs_len[] =
 
 
 /* Local version of `strdup' function.  */
-static inline char *
+static char *
 local_strdup (const char *s)
 {
   size_t len = strlen (s) + 1;
@@ -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
     {
@@ -258,7 +341,11 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
          ++name;
          if ((len = is_dst (start, name, "ORIGIN", is_path,
                             INTUSE(__libc_enable_secure))) != 0)
-           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);
          else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
@@ -277,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.  */
@@ -286,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;
@@ -303,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;
@@ -314,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)
@@ -328,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);
 }
 
 
@@ -373,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[] = "./";
@@ -400,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.  */
@@ -487,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.  */
@@ -496,7 +588,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 }
 
 
-static void
+static bool
 internal_function
 decompose_rpath (struct r_search_path_struct *sps,
                 const char *rpath, struct link_map *l, const char *what)
@@ -531,19 +623,8 @@ decompose_rpath (struct r_search_path_struct *sps,
            {
              /* This object is on the list of objects for which the
                 RUNPATH and RPATH must not be used.  */
-             result = calloc (1, sizeof *result);
-             if (result == NULL)
-               {
-               signal_error_cache:
-                 errstring = N_("cannot create cache for search path");
-               signal_error:
-                 _dl_signal_error (ENOMEM, NULL, NULL, errstring);
-               }
-
-             sps->dirs = result;
-             sps->malloced = 1;
-
-             return;
+             sps->dirs = (void *) -1;
+             return false;
            }
 
          while (*inhp != '\0')
@@ -553,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)
@@ -573,9 +661,14 @@ decompose_rpath (struct r_search_path_struct *sps,
   result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1)
                                                  * sizeof (*result));
   if (result == NULL)
-    goto signal_error_cache;
+    {
+      free (copy);
+      errstring = N_("cannot create cache for search path");
+    signal_error:
+      _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.  */
@@ -584,6 +677,7 @@ decompose_rpath (struct r_search_path_struct *sps,
   sps->dirs = result;
   /* The caller will change this value if we haven't used a real malloc.  */
   sps->malloced = 1;
+  return true;
 }
 
 /* Make sure cached path information is stored in *SP
@@ -608,10 +702,9 @@ cache_rpath (struct link_map *l,
     }
 
   /* Make sure the cache information is available.  */
-  decompose_rpath (sp, (const char *) (D_PTR (l, l_info[DT_STRTAB])
-                                      + l->l_info[tag]->d_un.d_val),
-                  l, what);
-  return true;
+  return decompose_rpath (sp, (const char *) (D_PTR (l, l_info[DT_STRTAB])
+                                             + l->l_info[tag]->d_un.d_val),
+                         l, what);
 }
 
 
@@ -623,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;
 
@@ -706,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;
@@ -722,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
@@ -734,7 +831,25 @@ _dl_init_paths (const char *llp)
     {
       size_t nllp;
       const char *cp = llp;
-      char *llp_tmp = strdupa (llp);
+      char *llp_tmp;
+
+#ifdef SHARED
+      /* Expand DSTs.  */
+      size_t cnt = DL_DST_COUNT (llp, 1);
+      if (__builtin_expect (cnt == 0, 1))
+       llp_tmp = strdupa (llp);
+      else
+       {
+         /* Determine the length of the substituted string.  */
+         size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
+
+         /* Allocate the necessary memory.  */
+         llp_tmp = (char *) alloca (total + 1);
+         llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
+       }
+#else
+      llp_tmp = strdupa (llp);
+#endif
 
       /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
         elements it has.  */
@@ -756,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)
        {
@@ -768,34 +883,29 @@ _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)
+      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)
+  if (l != NULL && l->l_origin != (char *) -1l)
+    free ((char *) l->l_origin);
+  free (l);
+  free (realname);
+
+  if (r != 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);
+      r->r_state = RT_CONSISTENT;
+      _dl_debug_state ();
+      LIBC_PROBE (map_failed, 2, nsid, r);
     }
-  free (realname);
+
   _dl_signal_error (code, name, NULL, msg);
 }
 
@@ -831,13 +941,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
     call_lose_errno:
       errval = errno;
     call_lose:
-      if (make_consistent)
-       {
-         r->r_state = RT_CONSISTENT;
-         _dl_debug_state ();
-       }
-
-      lose (errval, fd, name, realname, l, errstring);
+      lose (errval, fd, name, realname, l, errstring,
+           make_consistent ? r : NULL, nsid);
     }
 
   /* Look again to see if the real name matched another already loaded.  */
@@ -877,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))
@@ -900,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"));
@@ -912,7 +1025,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
     {
 #ifdef SHARED
       /* Auditing checkpoint: we are going to add new objects.  */
-      if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
+      if ((mode & __RTLD_AUDIT) == 0
+         && __builtin_expect (GLRO(dl_naudit) > 0, 0))
        {
          struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
          /* Do not call the functions for any auditing object.  */
@@ -935,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
@@ -971,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;
@@ -1050,7 +1167,6 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
          break;
 
        case PT_TLS:
-#ifdef USE_TLS
          if (ph->p_memsz == 0)
            /* Nothing to do for an empty segment.  */
            break;
@@ -1078,16 +1194,18 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
              break;
            }
 
-# ifdef SHARED
+#ifdef SHARED
          if (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0)
            /* We are loading the executable itself when the dynamic linker
               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.
                 We can do the TLS setup right now!  */
@@ -1120,7 +1238,6 @@ cannot allocate TLS data structures for initial thread");
              _dl_deallocate_tls (tcb, 1);
              goto call_lose;
            }
-#endif
 
          /* Uh-oh, the binary expects TLS support but we cannot
             provide it.  */
@@ -1175,7 +1292,7 @@ cannot allocate TLS data structures for initial thread");
        /* Remember which part of the address space this object uses.  */
        l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
                                              c->prot,
-                                             MAP_COPY | MAP_FILE,
+                                             MAP_COPY|MAP_FILE,
                                              fd, c->mapoff);
        if (__builtin_expect ((void *) l->l_map_start == MAP_FAILED, 0))
          {
@@ -1194,9 +1311,11 @@ cannot allocate TLS data structures for initial thread");
             handle the portion of the segment past the end of the file
             mapping.  */
          __mprotect ((caddr_t) (l->l_addr + c->mapend),
-                     loadcmds[nloadcmds - 1].allocend - c->mapend,
+                     loadcmds[nloadcmds - 1].mapstart - c->mapend,
                      PROT_NONE);
 
+       l->l_contiguous = 1;
+
        goto postmap;
       }
 
@@ -1216,6 +1335,7 @@ cannot allocate TLS data structures for initial thread");
     /* Remember which part of the address space this object uses.  */
     l->l_map_start = c->mapstart + l->l_addr;
     l->l_map_end = l->l_map_start + maplength;
+    l->l_contiguous = !has_holes;
 
     while (c < &loadcmds[nloadcmds])
       {
@@ -1223,7 +1343,7 @@ cannot allocate TLS data structures for initial thread");
            /* Map the segment contents from the file.  */
            && (__mmap ((void *) (l->l_addr + c->mapstart),
                        c->mapend - c->mapstart, c->prot,
-                       MAP_FIXED|MAP_COPY|MAP_FILE|MAP_DENYWRITE,
+                       MAP_FIXED|MAP_COPY|MAP_FILE,
                        fd, c->mapoff)
                == MAP_FAILED))
          goto map_error;
@@ -1233,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)
          {
@@ -1281,7 +1402,7 @@ cannot allocate TLS data structures for initial thread");
                caddr_t mapat;
                mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
                                c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
-                               ANONFD, 0);
+                               -1, 0);
                if (__builtin_expect (mapat == MAP_FAILED, 0))
                  {
                    errstring = N_("cannot map zero-fill pages");
@@ -1348,22 +1469,40 @@ cannot allocate TLS data structures for initial thread");
 
   if (__builtin_expect ((stack_flags &~ GL(dl_stack_flags)) & PF_X, 0))
     {
+      if (__builtin_expect (__check_caller (RETURN_ADDRESS (0), allow_ldso),
+                           0) != 0)
+       {
+         errstring = N_("invalid caller");
+         goto call_lose;
+       }
+
       /* The stack is presently not executable, but this module
         requires that it be executable.  We must change the
         protection of the variable which contains the flags used in
         the mprotect calls.  */
-#ifdef HAVE_Z_RELRO
+#ifdef SHARED
       if ((mode & (__RTLD_DLOPEN | __RTLD_AUDIT)) == __RTLD_DLOPEN)
        {
-         uintptr_t p = ((uintptr_t) &__stack_prot) & ~(GLRO(dl_pagesize) - 1);
-         size_t s = (uintptr_t) &__stack_prot - p + sizeof (int);
-
-         __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
-         if (__builtin_expect (__check_caller (RETURN_ADDRESS (0),
-                                               allow_ldso) == 0,
-                               0))
+         const uintptr_t p = (uintptr_t) &__stack_prot & -GLRO(dl_pagesize);
+         const size_t s = (uintptr_t) (&__stack_prot + 1) - p;
+
+         struct link_map *const m = &GL(dl_rtld_map);
+         const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
+                                       + m->l_relro_size)
+                                      & -GLRO(dl_pagesize));
+         if (__builtin_expect (p + s <= relro_end, 1))
+           {
+             /* The variable lies in the region protected by RELRO.  */
+             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);
+           }
+         else
            __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
-         __mprotect ((void *) p, s, PROT_READ);
        }
       else
 #endif
@@ -1382,11 +1521,9 @@ cannot enable executable stack as shared object requires");
        }
     }
 
-#ifdef USE_TLS
   /* Adjust the address of the TLS initialization image.  */
   if (l->l_tls_initimage != NULL)
     l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
-#endif
 
   /* We are done mapping in the file.  We no longer need the descriptor.  */
   if (__builtin_expect (__close (fd) != 0, 0))
@@ -1428,15 +1565,6 @@ cannot enable executable stack as shared object requires");
     {
       /* Create an appropriate searchlist.  It contains only this map.
         This is the definition of DT_SYMBOLIC in SysVr4.  */
-      l->l_symbolic_searchlist.r_list =
-       (struct link_map **) malloc (sizeof (struct link_map *));
-
-      if (l->l_symbolic_searchlist.r_list == NULL)
-       {
-         errstring = N_("cannot create searchlist");
-         goto call_lose_errno;
-       }
-
       l->l_symbolic_searchlist.r_list[0] = l;
       l->l_symbolic_searchlist.r_nlist = 1;
 
@@ -1463,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)
@@ -1490,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;
@@ -1520,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);
 }
@@ -1532,7 +1667,7 @@ print_search_path (struct r_search_path_elem **list,
    user might want to know about this.  */
 static int
 open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
-            int whatcode)
+            int whatcode, bool *found_other_class, bool free_name)
 {
   /* This is the expected ELF header.  */
 #define ELF32_CLASS ELFCLASS32
@@ -1540,9 +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,
@@ -1588,22 +1725,32 @@ 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;
       ElfW(Phdr) *phdr, *ph;
-      ElfW(Word) *abi_note, abi_note_buf[8];
+      ElfW(Word) *abi_note;
       unsigned int osversion;
       size_t maplength;
 
       /* 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.  */
@@ -1613,15 +1760,28 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
          errstring = (errval == 0
                       ? N_("file too short") : N_("cannot read file data"));
        call_lose:
-         lose (errval, fd, name, NULL, NULL, errstring);
+         if (free_name)
+           {
+             char *realname = (char *) name;
+             name = strdupa (realname);
+             free (realname);
+           }
+         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.  */
-         if (*(Elf32_Word *) &ehdr->e_ident !=
+         const Elf32_Word *magp = (const void *) ehdr->e_ident;
+         if (*magp !=
 #if BYTE_ORDER == LITTLE_ENDIAN
              ((ELFMAG0 << (EI_MAG0 * 8)) |
               (ELFMAG1 << (EI_MAG1 * 8)) |
@@ -1636,10 +1796,13 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
              )
            errstring = N_("invalid ELF header");
          else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS))
-           /* This is not a fatal error.  On architectures where
-              32-bit and 64-bit binaries can be run this might
-              happen.  */
-           goto close_and_out;
+           {
+             /* This is not a fatal error.  On architectures where
+                32-bit and 64-bit binaries can be run this might
+                happen.  */
+             *found_other_class = true;
+             goto close_and_out;
+           }
          else if (ehdr->e_ident[EI_DATA] != byteorder)
            {
              if (BYTE_ORDER == BIG_ENDIAN)
@@ -1654,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");
@@ -1701,20 +1868,37 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 
       /* Check .note.ABI-tag if present.  */
       for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
-       if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4)
+       if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
          {
-           if (ph->p_offset + 32 <= (size_t) fbp->len)
+           ElfW(Addr) size = ph->p_filesz;
+
+           if (ph->p_offset + size <= (size_t) fbp->len)
              abi_note = (void *) (fbp->buf + ph->p_offset);
            else
              {
+               abi_note = alloca (size);
                __lseek (fd, ph->p_offset, SEEK_SET);
-               if (__libc_read (fd, (void *) abi_note_buf, 32) != 32)
+               if (__libc_read (fd, (void *) abi_note, size) != size)
                  goto read_error;
+             }
+
+           while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+             {
+#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
+               ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
+                                      + ROUND (abi_note[0])
+                                      + ROUND (abi_note[1]);
 
-               abi_note = abi_note_buf;
+               if (size - 32 < note_size)
+                 {
+                   size = 0;
+                   break;
+                 }
+               size -= note_size;
+               abi_note = (void *) abi_note + note_size;
              }
 
-           if (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+           if (size == 0)
              continue;
 
            osversion = (abi_note[5] & 0xff) * 65536
@@ -1744,9 +1928,10 @@ 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)
+          struct filebuf *fbp, struct link_map *loader, int whatcode,
+          bool *found_other_class)
 {
   struct r_search_path_elem **dirs = sps->dirs;
   char *buf;
@@ -1795,7 +1980,8 @@ open_path (const char *name, size_t namelen, int preloaded,
          if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
            _dl_debug_printf ("  trying file=%s\n", buf);
 
-         fd = open_verify (buf, fbp, loader, whatcode);
+         fd = open_verify (buf, fbp, loader, whatcode, found_other_class,
+                           false);
          if (this_dir->status[cnt] == unknown)
            {
              if (fd != -1)
@@ -1804,7 +1990,7 @@ open_path (const char *name, size_t namelen, int preloaded,
                 auditing code.  We must try to disturb the program as
                 little as possible.  */
              else if (loader == NULL
-                      || GL(dl_ns)[loader->l_ns]._ns_loaded->l_audit == 0)
+                      || GL(dl_ns)[loader->l_ns]._ns_loaded->l_auditing == 0)
                {
                  /* We failed to open machine dependent library.  Let's
                     test whether there is any directory at all.  */
@@ -1824,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
@@ -1879,11 +2065,10 @@ open_path (const char *name, size_t namelen, int preloaded,
         must not be freed using the general free() in libc.  */
       if (sps->malloced)
        free (sps->dirs);
-#ifdef HAVE_Z_RELRO
+
       /* rtld_search_dirs is attribute_relro, therefore avoid writing
         into it.  */
       if (sps != &rtld_search_dirs)
-#endif
        sps->dirs = (void *) -1;
     }
 
@@ -1894,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;
@@ -1904,7 +2089,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
   struct filebuf fb;
 
   assert (nsid >= 0);
-  assert (nsid < DL_NNS);
+  assert (nsid < GL(dl_nns));
 
   /* Look for this name among those already loaded.  */
   for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
@@ -1940,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
@@ -1970,6 +2156,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
     }
 #endif
 
+  /* Will be true if we found a DSO which is of the other ELF class.  */
+  bool found_other_class = false;
+
   if (strchr (name, '/') == NULL)
     {
       /* Search for NAME in several places.  */
@@ -1982,46 +2171,61 @@ _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
+            we do not look at it twice.  */
+         struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+         bool did_main_map = false;
+
          /* First try the DT_RPATH of the dependent object that caused NAME
             to be loaded.  Then that object's dependent, and on up.  */
-         for (l = loader; fd == -1 && l; l = l->l_loader)
+         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,
-                             &realname, &fb, loader, LA_SER_RUNPATH);
+             {
+               fd = open_path (name, namelen, mode & __RTLD_SECURE,
+                               &l->l_rpath_dirs,
+                               &realname, &fb, loader, LA_SER_RUNPATH,
+                               &found_other_class);
+               if (fd != -1)
+                 break;
+
+               did_main_map |= l == main_map;
+             }
 
          /* If dynamically linked, try the DT_RPATH of the executable
-             itself.  NB: we do this for lookups in any namespace.  */
-         if (fd == -1)
-           {
-             l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-             if (l && l->l_type != lt_loaded && l != loader
-                 && cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
-               fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
-                               &realname, &fb, loader ?: l, LA_SER_RUNPATH);
-           }
+            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, 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);
+                       LA_SER_LIBPATH, &found_other_class);
 
       /* Look at the RUNPATH information for this binary.  */
       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);
+                       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.  */
@@ -2029,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;
@@ -2067,7 +2273,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
                {
                  fd = open_verify (cached,
                                    &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
-                                   LA_SER_CONFIG);
+                                   LA_SER_CONFIG, &found_other_class, false);
                  if (__builtin_expect (fd != -1, 1))
                    {
                      realname = local_strdup (cached);
@@ -2080,31 +2286,33 @@ _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,
-                       &realname, &fb, l, LA_SER_DEFAULT);
+       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;
       else
        {
          fd = open_verify (realname, &fb,
-                           loader ?: GL(dl_ns)[nsid]._ns_loaded, 0);
+                           loader ?: GL(dl_ns)[nsid]._ns_loaded, 0,
+                           &found_other_class, true);
          if (__builtin_expect (fd, 0) == -1)
            free (realname);
        }
@@ -2130,12 +2338,15 @@ _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)
-           _dl_signal_error (ENOMEM, name, NULL,
-                             N_("cannot create shared object descriptor"));
+           {
+             free (name_copy);
+             _dl_signal_error (ENOMEM, name, NULL,
+                               N_("cannot create shared object descriptor"));
+           }
          /* Signal that this is a faked entry.  */
          l->l_faked = 1;
          /* Since the descriptor is initialized with zero we do not
@@ -2145,8 +2356,16 @@ _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)
+       _dl_signal_error (0, name, NULL,
+                         ELFW(CLASS) == ELFCLASS32
+                         ? N_("wrong ELF class: ELFCLASS64")
+                         : N_("wrong ELF class: ELFCLASS32"));
       else
        _dl_signal_error (errno, name, NULL,
                          N_("cannot open shared object file"));
@@ -2182,14 +2401,17 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
              if (counting)
                {
                  si->dls_cnt++;
-                 si->dls_size += r->dirnamelen;
+                 si->dls_size += MAX (2, r->dirnamelen);
                }
              else
                {
                  Dl_serpath *const sp = &si->dls_serpath[idx++];
                  sp->dls_name = allocptr;
-                 allocptr = __mempcpy (allocptr,
-                                       r->dirname, r->dirnamelen - 1);
+                 if (r->dirnamelen < 2)
+                   *allocptr++ = r->dirnamelen ? '/' : '.';
+                 else
+                   allocptr = __mempcpy (allocptr,
+                                         r->dirname, r->dirnamelen - 1);
                  *allocptr++ = '\0';
                  sp->dls_flags = flags;
                }