]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/dl-load.c
Fix BZ 20419. A PT_NOTE in a binary could be arbitratily large, so using
[thirdparty/glibc.git] / elf / dl-load.c
index cfa7f2525fc6543fc3944f207dd29d5cc7102894..431236920f9d1b04fa98923195ca45f775262949 100644 (file)
@@ -1,5 +1,5 @@
 /* Map in a shared object's segments from the file.
-   Copyright (C) 1995-2014 Free Software Foundation, Inc.
+   Copyright (C) 1995-2018 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
 #include "dynamic-link.h"
 #include <abi-tag.h>
 #include <stackinfo.h>
-#include <caller.h>
 #include <sysdep.h>
 #include <stap-probe.h>
+#include <libc-pointer-arith.h>
+#include <array_length.h>
 
 #include <dl-dst.h>
 #include <dl-load.h>
 #include <dl-map-segments.h>
 #include <dl-unmap-segments.h>
+#include <dl-machine-reject-phdr.h>
+#include <dl-sysdep-open.h>
 
 
 #include <endian.h>
@@ -100,7 +103,9 @@ static size_t ncapstr attribute_relro;
 static size_t max_capstrlen attribute_relro;
 
 
-/* Get the generated information about the trusted directories.  */
+/* Get the generated information about the trusted directories.  Use
+   an array of concatenated strings to avoid relocations.  See
+   gen-trusted-dirs.awk.  */
 #include "trusted-dirs.h"
 
 static const char system_dirs[] = SYSTEM_DIRS;
@@ -108,41 +113,7 @@ static const size_t system_dirs_len[] =
 {
   SYSTEM_DIRS_LEN
 };
-#define nsystem_dirs_len \
-  (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-
-
-/* Local version of `strdup' function.  */
-static char *
-local_strdup (const char *s)
-{
-  size_t len = strlen (s) + 1;
-  void *new = malloc (len);
-
-  if (new == NULL)
-    return NULL;
-
-  return (char *) memcpy (new, s, len);
-}
-
-
-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;
-}
-
+#define nsystem_dirs_len array_length (system_dirs_len)
 
 static bool
 is_trusted_path_normalize (const char *path, size_t len)
@@ -208,8 +179,7 @@ is_trusted_path_normalize (const char *path, size_t len)
 
 
 static size_t
-is_dst (const char *start, const char *name, const char *str,
-       int is_path, int secure)
+is_dst (const char *start, const char *name, const char *str, int secure)
 {
   size_t len;
   bool is_curly = false;
@@ -234,14 +204,12 @@ is_dst (const char *start, const char *name, const char *str,
       /* Skip over closing curly brace and adjust for the --name.  */
       len += 2;
     }
-  else if (name[len] != '\0' && name[len] != '/'
-          && (!is_path || name[len] != ':'))
+  else if (name[len] != '\0' && name[len] != '/')
     return 0;
 
   if (__glibc_unlikely (secure)
-      && ((name[len] != '\0' && name[len] != '/'
-          && (!is_path || name[len] != ':'))
-         || (name != start + 1 && (!is_path || name[-2] != ':'))))
+      && ((name[len] != '\0' && name[len] != '/')
+         || (name != start + 1)))
     return 0;
 
   return len;
@@ -249,7 +217,7 @@ is_dst (const char *start, const char *name, const char *str,
 
 
 size_t
-_dl_dst_count (const char *name, int is_path)
+_dl_dst_count (const char *name)
 {
   const char *const start = name;
   size_t cnt = 0;
@@ -261,10 +229,9 @@ _dl_dst_count (const char *name, int is_path)
       /* $ORIGIN is not expanded for SUID/GUID programs (except if it
         is $ORIGIN alone) and it must always appear first in path.  */
       ++name;
-      if ((len = is_dst (start, name, "ORIGIN", is_path,
-                        INTUSE(__libc_enable_secure))) != 0
-         || (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
-         || (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+      if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0
+         || (len = is_dst (start, name, "PLATFORM", 0)) != 0
+         || (len = is_dst (start, name, "LIB", 0)) != 0)
        ++cnt;
 
       name = strchr (name + len, '$');
@@ -276,8 +243,7 @@ _dl_dst_count (const char *name, int is_path)
 
 
 char *
-_dl_dst_substitute (struct link_map *l, const char *name, char *result,
-                   int is_path)
+_dl_dst_substitute (struct link_map *l, const char *name, char *result)
 {
   const char *const start = name;
 
@@ -297,16 +263,15 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
          size_t len;
 
          ++name;
-         if ((len = is_dst (start, name, "ORIGIN", is_path,
-                            INTUSE(__libc_enable_secure))) != 0)
+         if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0)
            {
              repl = l->l_origin;
-             check_for_trusted = (INTUSE(__libc_enable_secure)
+             check_for_trusted = (__libc_enable_secure
                                   && l->l_type == lt_executable);
            }
-         else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+         else if ((len = is_dst (start, name, "PLATFORM", 0)) != 0)
            repl = GLRO(dl_platform);
-         else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+         else if ((len = is_dst (start, name, "LIB", 0)) != 0)
            repl = DL_DST_LIB;
 
          if (repl != NULL && repl != (const char *) -1)
@@ -319,13 +284,7 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
              /* We cannot use this path element, the value of the
                 replacement is unknown.  */
              wp = last_elem;
-             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;
+             break;
            }
          else
            /* No DST we recognize.  */
@@ -334,19 +293,6 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
       else
        {
          *wp++ = *name++;
-         if (is_path && *name == ':')
-           {
-             /* In SUID/SGID programs, after $ORIGIN expansion the
-                normalized path must be rooted in one of the trusted
-                directories.  */
-             if (__glibc_unlikely (check_for_trusted)
-                 && !is_trusted_path_normalize (last_elem, wp - last_elem))
-               wp = last_elem;
-             else
-               last_elem = wp;
-
-             check_for_trusted = false;
-           }
        }
     }
   while (*name != '\0');
@@ -369,7 +315,7 @@ _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, int is_path)
+expand_dynamic_string_token (struct link_map *l, const char *s)
 {
   /* 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 no
@@ -380,11 +326,11 @@ expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
   char *result;
 
   /* Determine the number of DST elements.  */
-  cnt = DL_DST_COUNT (s, is_path);
+  cnt = DL_DST_COUNT (s);
 
   /* If we do not have to replace anything simply copy the string.  */
   if (__glibc_likely (cnt == 0))
-    return local_strdup (s);
+    return __strdup (s);
 
   /* Determine the length of the substituted string.  */
   total = DL_DST_REQUIRED (l, s, strlen (s), cnt);
@@ -394,7 +340,7 @@ expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
   if (result == NULL)
     return NULL;
 
-  return _dl_dst_substitute (l, s, result, is_path);
+  return _dl_dst_substitute (l, s, result);
 }
 
 
@@ -403,7 +349,6 @@ expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
    be freed if the shared object already has this name.
    Returns false if the object already had this name.  */
 static void
-internal_function
 add_name_to_object (struct link_map *l, const char *name)
 {
   struct libname_list *lnp, *lastp;
@@ -439,42 +384,43 @@ 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,
-             struct link_map *l)
+             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;
+      char *to_free = NULL;
+      size_t len = 0;
 
-      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'. */
-      if (len == 0)
+      /* `strsep' can pass an empty string.  */
+      if (*cp != '\0')
        {
-         static const char curwd[] = "./";
-         cp = (char *) curwd;
-       }
+         to_free = cp = expand_dynamic_string_token (l, cp);
+
+         /* expand_dynamic_string_token can return NULL in case of empty
+            path or memory allocation failure.  */
+         if (cp == NULL)
+           continue;
 
-      /* Remove trailing slashes (except for "/").  */
-      while (len > 1 && cp[len - 1] == '/')
-       --len;
+         /* Compute the length after dynamic string token expansion and
+            ignore empty paths.  */
+         len = strlen (cp);
+         if (len == 0)
+           {
+             free (to_free);
+             continue;
+           }
 
-      /* Now add one if there is none so far.  */
-      if (len > 0 && cp[len - 1] != '/')
-       cp[len++] = '/';
+         /* Remove trailing slashes (except for "/").  */
+         while (len > 1 && cp[len - 1] == '/')
+           --len;
 
-      /* Make sure we don't use untrusted directories if we run SUID.  */
-      if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len))
-       {
-         free (to_free);
-         continue;
+         /* Now add one if there is none so far.  */
+         if (len > 0 && cp[len - 1] != '/')
+           cp[len++] = '/';
        }
 
       /* See if this directory is already known.  */
@@ -547,13 +493,11 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 
 
 static bool
-internal_function
 decompose_rpath (struct r_search_path_struct *sps,
                 const char *rpath, struct link_map *l, const char *what)
 {
   /* Make a copy we can work with.  */
   const char *where = l->l_name;
-  char *copy;
   char *cp;
   struct r_search_path_elem **result;
   size_t nelems;
@@ -563,7 +507,7 @@ decompose_rpath (struct r_search_path_struct *sps,
   /* First see whether we must forget the RUNPATH and RPATH from this
      object.  */
   if (__glibc_unlikely (GLRO(dl_inhibit_rpath) != NULL)
-      && !INTUSE(__libc_enable_secure))
+      && !__libc_enable_secure)
     {
       const char *inhp = GLRO(dl_inhibit_rpath);
 
@@ -592,22 +536,21 @@ decompose_rpath (struct r_search_path_struct *sps,
       while (*inhp != '\0');
     }
 
+  /* Ignore empty rpaths.  */
+  if (*rpath == '\0')
+    {
+      sps->dirs = (struct r_search_path_elem **) -1;
+      return false;
+    }
+
   /* Make a writable copy.  */
-  copy = local_strdup (rpath);
+  char *copy = __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)
@@ -626,12 +569,20 @@ decompose_rpath (struct r_search_path_struct *sps,
       _dl_signal_error (ENOMEM, NULL, NULL, errstring);
     }
 
-  fillin_rpath (copy, result, ":", 0, what, where, l);
+  fillin_rpath (copy, result, ":", what, where, l);
 
   /* Free the copied RPATH string.  `fillin_rpath' make own copies if
      necessary.  */
   free (copy);
 
+  /* There is no path after expansion.  */
+  if (result[0] == NULL)
+    {
+      free (result);
+      sps->dirs = (struct r_search_path_elem **) -1;
+      return false;
+    }
+
   sps->dirs = result;
   /* The caller will change this value if we haven't used a real malloc.  */
   sps->malloced = 1;
@@ -667,7 +618,6 @@ cache_rpath (struct link_map *l,
 
 
 void
-internal_function
 _dl_init_paths (const char *llp)
 {
   size_t idx;
@@ -699,9 +649,8 @@ _dl_init_paths (const char *llp)
                 + ncapstr * sizeof (enum r_dir_status))
                / sizeof (struct r_search_path_elem));
 
-  rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
-    malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
-           * round_size * sizeof (struct r_search_path_elem));
+  rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
+                                    * sizeof (*rtld_search_dirs.dirs[0]));
   if (rtld_search_dirs.dirs[0] == NULL)
     {
       errstring = N_("cannot create cache for search path");
@@ -787,37 +736,14 @@ _dl_init_paths (const char *llp)
 
   if (llp != NULL && *llp != '\0')
     {
-      size_t nllp;
-      const char *cp = llp;
-      char *llp_tmp;
-
-#ifdef SHARED
-      /* Expand DSTs.  */
-      size_t cnt = DL_DST_COUNT (llp, 1);
-      if (__glibc_likely (cnt == 0))
-       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
+      char *llp_tmp = strdupa (llp);
 
       /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
         elements it has.  */
-      nllp = 1;
-      while (*cp)
-       {
-         if (*cp == ':' || *cp == ';')
-           ++nllp;
-         ++cp;
-       }
+      size_t nllp = 1;
+      for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
+       if (*cp == ':' || *cp == ';')
+         ++nllp;
 
       env_path_list.dirs = (struct r_search_path_elem **)
        malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
@@ -828,8 +754,7 @@ _dl_init_paths (const char *llp)
        }
 
       (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
-                          INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH",
-                          NULL, l);
+                          "LD_LIBRARY_PATH", NULL, l);
 
       if (env_path_list.dirs[0] == NULL)
        {
@@ -875,9 +800,10 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
 static
 #endif
 struct link_map *
-_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
-                       char *realname, struct link_map *loader, int l_type,
-                       int mode, void **stack_endp, Lmid_t nsid)
+_dl_map_object_from_fd (const char *name, const char *origname, int fd,
+                       struct filebuf *fbp, char *realname,
+                       struct link_map *loader, int l_type, int mode,
+                       void **stack_endp, Lmid_t nsid)
 {
   struct link_map *l = NULL;
   const ElfW(Ehdr) *header;
@@ -885,7 +811,6 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   const ElfW(Phdr) *ph;
   size_t maplength;
   int type;
-  struct stat64 st;
   /* Initialize to keep the compiler happy.  */
   const char *errstring = NULL;
   int errval = 0;
@@ -893,7 +818,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   bool make_consistent = false;
 
   /* Get file information.  */
-  if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &st) < 0))
+  struct r_file_id id;
+  if (__glibc_unlikely (!_dl_get_file_id (fd, &id)))
     {
       errstring = N_("cannot stat shared object");
     call_lose_errno:
@@ -904,8 +830,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
     }
 
   /* Look again to see if the real name matched another already loaded.  */
-  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
-    if (l->l_removed == 0 && l->l_ino == st.st_ino && l->l_dev == st.st_dev)
+  for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+    if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
       {
        /* The object is already loaded.
           Just bump its reference count and return it.  */
@@ -923,8 +849,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   /* When loading into a namespace other than the base one we must
      avoid loading ld.so since there can only be one copy.  Ever.  */
   if (__glibc_unlikely (nsid != LM_ID_BASE)
-      && ((st.st_ino == GL(dl_rtld_map).l_ino
-          && st.st_dev == GL(dl_rtld_map).l_dev)
+      && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
          || _dl_name_match_p (name, &GL(dl_rtld_map))))
     {
       /* This is indeed ld.so.  Create a new link_map which refers to
@@ -1066,8 +991,14 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
             segments are mapped in.  We record the addresses it says
             verbatim, and later correct for the run-time load address.  */
        case PT_DYNAMIC:
-         l->l_ld = (void *) ph->p_vaddr;
-         l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+         if (ph->p_filesz)
+           {
+             /* Debuginfo only files from "objcopy --only-keep-debug"
+                contain a PT_DYNAMIC segment with p_filesz == 0.  Skip
+                such a segment to avoid a crash later.  */
+             l->l_ld = (void *) ph->p_vaddr;
+             l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+           }
          break;
 
        case PT_PHDR:
@@ -1091,12 +1022,11 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
            }
 
          struct loadcmd *c = &loadcmds[nloadcmds++];
-         c->mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
-         c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
-                      & ~(GLRO(dl_pagesize) - 1));
+         c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
+         c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
          c->dataend = ph->p_vaddr + ph->p_filesz;
          c->allocend = ph->p_vaddr + ph->p_memsz;
-         c->mapoff = ph->p_offset & ~(GLRO(dl_pagesize) - 1);
+         c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
 
          /* Determine whether there is a gap between the last segment
             and this one.  */
@@ -1147,54 +1077,14 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
            }
 
 #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
+         /* We are loading the executable itself when the dynamic
+            linker was executed directly.  The setup will happen
+            later.  Otherwise, the TLS data structures are already
+            initialized, and we assigned a TLS modid above.  */
+         assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
+#else
+         assert (false && "TLS not initialized in static application");
 #endif
-           {
-             /* We have not yet loaded libpthread.
-                We can do the TLS setup right now!  */
-
-             void *tcb;
-
-             /* The first call allocates TLS bookkeeping data structures.
-                Then we allocate the TCB for the initial thread.  */
-             if (__glibc_unlikely (_dl_tls_setup ())
-                 || __glibc_unlikely ((tcb = _dl_allocate_tls (NULL)) == NULL))
-               {
-                 errval = ENOMEM;
-                 errstring = N_("\
-cannot allocate TLS data structures for initial thread");
-                 goto call_lose;
-               }
-
-             /* Now we install the TCB in the thread register.  */
-             errstring = TLS_INIT_TP (tcb, 0);
-             if (__glibc_likely (errstring == NULL))
-               {
-                 /* Now we are all good.  */
-                 l->l_tls_modid = ++GL(dl_tls_max_dtv_idx);
-                 break;
-               }
-
-             /* The kernel is too old or somesuch.  */
-             errval = 0;
-             _dl_deallocate_tls (tcb, 1);
-             goto call_lose;
-           }
-
-         /* Uh-oh, the binary expects TLS support but we cannot
-            provide it.  */
-         errval = 0;
-         errstring = N_("cannot handle TLS data");
-         goto call_lose;
          break;
 
        case PT_GNU_STACK:
@@ -1233,7 +1123,7 @@ cannot allocate TLS data structures for initial thread");
        l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
      */
     errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
-                                  maplength, has_holes, loader);
+                                 maplength, has_holes, loader);
     if (__glibc_unlikely (errstring != NULL))
       goto call_lose;
   }
@@ -1292,12 +1182,6 @@ cannot allocate TLS data structures for initial thread");
 
   if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
     {
-      if (__glibc_unlikely (__check_caller (RETURN_ADDRESS (0), allow_ldso) != 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
@@ -1403,8 +1287,18 @@ cannot enable executable stack as shared object requires");
     GL(dl_initfirst) = l;
 
   /* Finally the file information.  */
-  l->l_dev = st.st_dev;
-  l->l_ino = st.st_ino;
+  l->l_file_id = id;
+
+#ifdef SHARED
+  /* When auditing is used the recorded names might not include the
+     name by which the DSO is actually known.  Add that as well.  */
+  if (__glibc_unlikely (origname != NULL))
+    add_name_to_object (l, origname);
+#else
+  /* Audit modules only exist when linking is dynamic so ORIGNAME
+     cannot be non-NULL.  */
+  assert (origname == NULL);
+#endif
 
   /* When we profile the SONAME might be needed for something else but
      loading.  Add it right away.  */
@@ -1486,9 +1380,13 @@ print_search_path (struct r_search_path_elem **list,
    ignore only ELF files for other architectures.  Non-ELF files and
    ELF files with different header information cause fatal errors since
    this could mean there is something wrong in the installation and the
-   user might want to know about this.  */
+   user might want to know about this.
+
+   If FD is not -1, then the file is already open and FD refers to it.
+   In that case, FD is consumed for both successful and error returns.  */
 static int
-open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
+open_verify (const char *name, int fd,
+             struct filebuf *fbp, struct link_map *loader,
             int whatcode, int mode, bool *found_other_class, bool free_name)
 {
   /* This is the expected ELF header.  */
@@ -1529,6 +1427,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
   if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0
       && loader->l_auditing == 0)
     {
+      const char *original_name = name;
       struct audit_ifaces *afct = GLRO(dl_audit);
       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
        {
@@ -1543,16 +1442,27 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 
          afct = afct->next;
        }
+
+      if (fd != -1 && name != original_name && strcmp (name, original_name))
+        {
+          /* An audit library changed what we're supposed to open,
+             so FD no longer matches it.  */
+          __close (fd);
+          fd = -1;
+        }
     }
 #endif
 
-  /* Open the file.  We always open files read-only.  */
-  int fd = __open (name, O_RDONLY | O_CLOEXEC);
+  if (fd == -1)
+    /* Open the file.  We always open files read-only.  */
+    fd = __open (name, O_RDONLY | O_CLOEXEC);
+
   if (fd != -1)
     {
       ElfW(Ehdr) *ehdr;
       ElfW(Phdr) *phdr, *ph;
       ElfW(Word) *abi_note;
+      ElfW(Word) *abi_note_malloced = NULL;
       unsigned int osversion;
       size_t maplength;
 
@@ -1697,28 +1607,59 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
            }
        }
 
+      if (__glibc_unlikely (elf_machine_reject_phdr_p
+                           (phdr, ehdr->e_phnum, fbp->buf, fbp->len,
+                            loader, fd)))
+       goto close_and_out;
+
       /* 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)
          {
            ElfW(Addr) size = ph->p_filesz;
+           /* NB: Some PT_NOTE segment may have alignment value of 0
+              or 1.  gABI specifies that PT_NOTE segments should be
+              aligned to 4 bytes in 32-bit objects and to 8 bytes in
+              64-bit objects.  As a Linux extension, we also support
+              4 byte alignment in 64-bit objects.  If p_align is less
+              than 4, we treate alignment as 4 bytes since some note
+              segments have 0 or 1 byte alignment.   */
+           ElfW(Addr) align = ph->p_align;
+           if (align < 4)
+             align = 4;
+           else if (align != 4 && align != 8)
+             continue;
 
            if (ph->p_offset + size <= (size_t) fbp->len)
              abi_note = (void *) (fbp->buf + ph->p_offset);
            else
              {
-               abi_note = alloca (size);
+               /* Note: __libc_use_alloca is not usable here, because
+                  thread info may not have been set up yet.  */
+               if (size < __MAX_ALLOCA_CUTOFF)
+                 abi_note = alloca (size);
+               else
+                 {
+                   /* There could be multiple PT_NOTEs.  */
+                   abi_note_malloced = realloc (abi_note_malloced, size);
+                   if (abi_note_malloced == NULL)
+                     goto read_error;
+
+                   abi_note = abi_note_malloced;
+                 }
                __lseek (fd, ph->p_offset, SEEK_SET);
                if (__libc_read (fd, (void *) abi_note, size) != size)
-                 goto read_error;
+                 {
+                   free (abi_note_malloced);
+                   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]);
+               ElfW(Addr) note_size
+                 = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1],
+                                         align);
 
                if (size - 32 < note_size)
                  {
@@ -1746,6 +1687,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 
            break;
          }
+      free (abi_note_malloced);
     }
 
   return fd;
@@ -1811,7 +1753,7 @@ open_path (const char *name, size_t namelen, int mode,
          if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
            _dl_debug_printf ("  trying file=%s\n", buf);
 
-         fd = open_verify (buf, fbp, loader, whatcode, mode,
+         fd = open_verify (buf, -1, fbp, loader, whatcode, mode,
                            found_other_class, false);
          if (this_dir->status[cnt] == unknown)
            {
@@ -1842,7 +1784,7 @@ open_path (const char *name, size_t namelen, int mode,
          here_any |= this_dir->status[cnt] != nonexisting;
 
          if (fd != -1 && __glibc_unlikely (mode & __RTLD_SECURE)
-             && INTUSE(__libc_enable_secure))
+             && __libc_enable_secure)
            {
              /* This is an extra security effort to make sure nobody can
                 preload broken shared objects which are in the trusted
@@ -1897,9 +1839,9 @@ open_path (const char *name, size_t namelen, int mode,
       if (sps->malloced)
        free (sps->dirs);
 
-      /* rtld_search_dirs is attribute_relro, therefore avoid writing
-        into it.  */
-      if (sps != &rtld_search_dirs)
+      /* rtld_search_dirs and env_path_list are attribute_relro, therefore
+        avoid writing into it.  */
+      if (sps != &rtld_search_dirs && sps != &env_path_list)
        sps->dirs = (void *) -1;
     }
 
@@ -1909,11 +1851,11 @@ open_path (const char *name, size_t namelen, int mode,
 /* Map in the shared object file NAME.  */
 
 struct link_map *
-internal_function
 _dl_map_object (struct link_map *loader, const char *name,
                int type, int trace_mode, int mode, Lmid_t nsid)
 {
   int fd;
+  const char *origname = NULL;
   char *realname;
   char *name_copy;
   struct link_map *l;
@@ -1971,6 +1913,7 @@ _dl_map_object (struct link_map *loader, const char *name,
        {
          if (afct->objsearch != NULL)
            {
+             const char *before = name;
              name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
                                      LA_SER_ORIG);
              if (name == NULL)
@@ -1979,6 +1922,15 @@ _dl_map_object (struct link_map *loader, const char *name,
                  fd = -1;
                  goto no_file;
                }
+             if (before != name && strcmp (before, name) != 0)
+               {
+                 if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+                   _dl_debug_printf ("audit changed filename %s -> %s\n",
+                                     before, name);
+
+                 if (origname == NULL)
+                   origname = before;
+               }
            }
 
          afct = afct->next;
@@ -2051,15 +2003,29 @@ _dl_map_object (struct link_map *loader, const char *name,
                        &loader->l_runpath_dirs, &realname, &fb, loader,
                        LA_SER_RUNPATH, &found_other_class);
 
+      if (fd == -1)
+        {
+          realname = _dl_sysdep_open_object (name, namelen, &fd);
+          if (realname != NULL)
+            {
+              fd = open_verify (realname, fd,
+                                &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
+                                LA_SER_CONFIG, mode, &found_other_class,
+                                false);
+              if (fd == -1)
+                free (realname);
+            }
+        }
+
 #ifdef USE_LDCONFIG
       if (fd == -1
          && (__glibc_likely ((mode & __RTLD_SECURE) == 0)
-             || ! INTUSE(__libc_enable_secure))
+             || ! __libc_enable_secure)
          && __glibc_likely (GLRO(dl_inhibit_cache) == 0))
        {
          /* Check the list of libraries in the file /etc/ld.so.cache,
             for compatibility with Linux's ldconfig program.  */
-         const char *cached = _dl_load_cache_lookup (name);
+         char *cached = _dl_load_cache_lookup (name);
 
          if (cached != NULL)
            {
@@ -2083,6 +2049,7 @@ _dl_map_object (struct link_map *loader, const char *name,
                      if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
                        {
                          /* The prefix matches.  Don't use the entry.  */
+                         free (cached);
                          cached = NULL;
                          break;
                        }
@@ -2095,19 +2062,14 @@ _dl_map_object (struct link_map *loader, const char *name,
 
              if (cached != NULL)
                {
-                 fd = open_verify (cached,
+                 fd = open_verify (cached, -1,
                                    &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
                                    LA_SER_CONFIG, mode, &found_other_class,
                                    false);
                  if (__glibc_likely (fd != -1))
-                   {
-                     realname = local_strdup (cached);
-                     if (realname == NULL)
-                       {
-                         __close (fd);
-                         fd = -1;
-                       }
-                   }
+                   realname = cached;
+                 else
+                   free (cached);
                }
            }
        }
@@ -2129,13 +2091,13 @@ _dl_map_object (struct link_map *loader, const char *name,
     {
       /* The path may contain dynamic string tokens.  */
       realname = (loader
-                 ? expand_dynamic_string_token (loader, name, 0)
-                 : local_strdup (name));
+                 ? expand_dynamic_string_token (loader, name)
+                 : __strdup (name));
       if (realname == NULL)
        fd = -1;
       else
        {
-         fd = open_verify (realname, &fb,
+         fd = open_verify (realname, -1, &fb,
                            loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
                            &found_other_class, true);
          if (__glibc_unlikely (fd == -1))
@@ -2164,7 +2126,7 @@ _dl_map_object (struct link_map *loader, const char *name,
          static const Elf_Symndx dummy_bucket = STN_UNDEF;
 
          /* Allocate a new object map.  */
-         if ((name_copy = local_strdup (name)) == NULL
+         if ((name_copy = __strdup (name)) == NULL
              || (l = _dl_new_object (name_copy, name, type, loader,
                                      mode, nsid)) == NULL)
            {
@@ -2197,13 +2159,51 @@ _dl_map_object (struct link_map *loader, const char *name,
     }
 
   void *stack_end = __libc_stack_end;
-  return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
-                                &stack_end, nsid);
+  return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
+                                type, mode, &stack_end, nsid);
 }
 
+struct add_path_state
+{
+  bool counting;
+  unsigned int idx;
+  Dl_serinfo *si;
+  char *allocptr;
+};
+
+static void
+add_path (struct add_path_state *p, const struct r_search_path_struct *sps,
+         unsigned int flags)
+{
+  if (sps->dirs != (void *) -1)
+    {
+      struct r_search_path_elem **dirs = sps->dirs;
+      do
+       {
+         const struct r_search_path_elem *const r = *dirs++;
+         if (p->counting)
+           {
+             p->si->dls_cnt++;
+             p->si->dls_size += MAX (2, r->dirnamelen);
+           }
+         else
+           {
+             Dl_serpath *const sp = &p->si->dls_serpath[p->idx++];
+             sp->dls_name = p->allocptr;
+             if (r->dirnamelen < 2)
+               *p->allocptr++ = r->dirnamelen ? '/' : '.';
+             else
+               p->allocptr = __mempcpy (p->allocptr,
+                                         r->dirname, r->dirnamelen - 1);
+             *p->allocptr++ = '\0';
+             sp->dls_flags = flags;
+           }
+       }
+      while (*dirs != NULL);
+    }
+}
 
 void
-internal_function
 _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
 {
   if (counting)
@@ -2212,38 +2212,15 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
       si->dls_size = 0;
     }
 
-  unsigned int idx = 0;
-  char *allocptr = (char *) &si->dls_serpath[si->dls_cnt];
-  void add_path (const struct r_search_path_struct *sps, unsigned int flags)
-# define add_path(sps, flags) add_path(sps, 0) /* XXX */
+  struct add_path_state p =
     {
-      if (sps->dirs != (void *) -1)
-       {
-         struct r_search_path_elem **dirs = sps->dirs;
-         do
-           {
-             const struct r_search_path_elem *const r = *dirs++;
-             if (counting)
-               {
-                 si->dls_cnt++;
-                 si->dls_size += MAX (2, r->dirnamelen);
-               }
-             else
-               {
-                 Dl_serpath *const sp = &si->dls_serpath[idx++];
-                 sp->dls_name = allocptr;
-                 if (r->dirnamelen < 2)
-                   *allocptr++ = r->dirnamelen ? '/' : '.';
-                 else
-                   allocptr = __mempcpy (allocptr,
-                                         r->dirname, r->dirnamelen - 1);
-                 *allocptr++ = '\0';
-                 sp->dls_flags = flags;
-               }
-           }
-         while (*dirs != NULL);
-       }
-    }
+      .counting = counting,
+      .idx = 0,
+      .si = si,
+      .allocptr = (char *) &si->dls_serpath[si->dls_cnt]
+    };
+
+# define add_path(p, sps, flags) add_path(p, sps, 0) /* XXX */
 
   /* When the object has the RUNPATH information we don't use any RPATHs.  */
   if (loader->l_info[DT_RUNPATH] == NULL)
@@ -2255,7 +2232,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
       do
        {
          if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
-           add_path (&l->l_rpath_dirs, XXX_RPATH);
+           add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
          l = l->l_loader;
        }
       while (l != NULL);
@@ -2266,16 +2243,16 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
          l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
          if (l != NULL && l->l_type != lt_loaded && l != loader)
            if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
-             add_path (&l->l_rpath_dirs, XXX_RPATH);
+             add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
        }
     }
 
   /* Try the LD_LIBRARY_PATH environment variable.  */
-  add_path (&env_path_list, XXX_ENV);
+  add_path (&p, &env_path_list, XXX_ENV);
 
   /* Look at the RUNPATH information for this binary.  */
   if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH"))
-    add_path (&loader->l_runpath_dirs, XXX_RUNPATH);
+    add_path (&p, &loader->l_runpath_dirs, XXX_RUNPATH);
 
   /* XXX
      Here is where ld.so.cache gets checked, but we don't have
@@ -2283,7 +2260,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
 
   /* Finally, try the default path.  */
   if (!(loader->l_flags_1 & DF_1_NODEFLIB))
-    add_path (&rtld_search_dirs, XXX_default);
+    add_path (&p, &rtld_search_dirs, XXX_default);
 
   if (counting)
     /* Count the struct size before the string area, which we didn't