hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame elf/dl-load.c

Packit 6c4009
/* Map in a shared object's segments from the file.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <elf.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <bits/wordsize.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
Packit 6c4009
/* Type for the buffer we put the ELF header and hopefully the program
Packit 6c4009
   header.  This buffer does not really have to be too large.  In most
Packit 6c4009
   cases the program header follows the ELF header directly.  If this
Packit 6c4009
   is not the case all bets are off and we can make the header
Packit 6c4009
   arbitrarily large and still won't get it read.  This means the only
Packit 6c4009
   question is how large are the ELF and program header combined.  The
Packit 6c4009
   ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
Packit 6c4009
   bytes long.  Each program header entry is again 32 and 56 bytes
Packit 6c4009
   long respectively.  I.e., even with a file which has 10 program
Packit 6c4009
   header entries we only have to read 372B/624B respectively.  Add to
Packit 6c4009
   this a bit of margin for program notes and reading 512B and 832B
Packit 6c4009
   for 32-bit and 64-bit files respecitvely is enough.  If this
Packit 6c4009
   heuristic should really fail for some file the code in
Packit 6c4009
   `_dl_map_object_from_fd' knows how to recover.  */
Packit 6c4009
struct filebuf
Packit 6c4009
{
Packit 6c4009
  ssize_t len;
Packit 6c4009
#if __WORDSIZE == 32
Packit 6c4009
# define FILEBUF_SIZE 512
Packit 6c4009
#else
Packit 6c4009
# define FILEBUF_SIZE 832
Packit 6c4009
#endif
Packit 6c4009
  char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
#include "dynamic-link.h"
Packit 6c4009
#include <abi-tag.h>
Packit 6c4009
#include <stackinfo.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <stap-probe.h>
Packit 6c4009
#include <libc-pointer-arith.h>
Packit 6c4009
#include <array_length.h>
Packit 6c4009
Packit 6c4009
#include <dl-dst.h>
Packit 6c4009
#include <dl-load.h>
Packit 6c4009
#include <dl-map-segments.h>
Packit 6c4009
#include <dl-unmap-segments.h>
Packit 6c4009
#include <dl-machine-reject-phdr.h>
Packit 6c4009
#include <dl-sysdep-open.h>
Packit 6c4009
#include <dl-prop.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
Packit 6c4009
#include <endian.h>
Packit 6c4009
#if BYTE_ORDER == BIG_ENDIAN
Packit 6c4009
# define byteorder ELFDATA2MSB
Packit 6c4009
#elif BYTE_ORDER == LITTLE_ENDIAN
Packit 6c4009
# define byteorder ELFDATA2LSB
Packit 6c4009
#else
Packit 6c4009
# error "Unknown BYTE_ORDER " BYTE_ORDER
Packit 6c4009
# define byteorder ELFDATANONE
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define STRING(x) __STRING (x)
Packit 6c4009
Packit 6c4009
Packit 6c4009
int __stack_prot attribute_hidden attribute_relro
Packit 6c4009
#if _STACK_GROWS_DOWN && defined PROT_GROWSDOWN
Packit 6c4009
  = PROT_GROWSDOWN;
Packit 6c4009
#elif _STACK_GROWS_UP && defined PROT_GROWSUP
Packit 6c4009
  = PROT_GROWSUP;
Packit 6c4009
#else
Packit 6c4009
  = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This is the decomposed LD_LIBRARY_PATH search path.  */
Packit 6c4009
static struct r_search_path_struct env_path_list attribute_relro;
Packit 6c4009
Packit 6c4009
/* List of the hardware capabilities we might end up using.  */
Packit 6c4009
static const struct r_strlenpair *capstr attribute_relro;
Packit 6c4009
static size_t ncapstr attribute_relro;
Packit 6c4009
static size_t max_capstrlen attribute_relro;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Get the generated information about the trusted directories.  Use
Packit 6c4009
   an array of concatenated strings to avoid relocations.  See
Packit 6c4009
   gen-trusted-dirs.awk.  */
Packit 6c4009
#include "trusted-dirs.h"
Packit 6c4009
Packit 6c4009
static const char system_dirs[] = SYSTEM_DIRS;
Packit 6c4009
static const size_t system_dirs_len[] =
Packit 6c4009
{
Packit 6c4009
  SYSTEM_DIRS_LEN
Packit 6c4009
};
Packit 6c4009
#define nsystem_dirs_len array_length (system_dirs_len)
Packit 6c4009
Packit 6c4009
static bool
Packit 6c4009
is_trusted_path_normalize (const char *path, size_t len)
Packit 6c4009
{
Packit 6c4009
  if (len == 0)
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  char *npath = (char *) alloca (len + 2);
Packit 6c4009
  char *wnp = npath;
Packit 6c4009
  while (*path != '\0')
Packit 6c4009
    {
Packit 6c4009
      if (path[0] == '/')
Packit 6c4009
	{
Packit 6c4009
	  if (path[1] == '.')
Packit 6c4009
	    {
Packit 6c4009
	      if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
Packit 6c4009
		{
Packit 6c4009
		  while (wnp > npath && *--wnp != '/')
Packit 6c4009
		    ;
Packit 6c4009
		  path += 3;
Packit 6c4009
		  continue;
Packit 6c4009
		}
Packit 6c4009
	      else if (path[2] == '/' || path[2] == '\0')
Packit 6c4009
		{
Packit 6c4009
		  path += 2;
Packit 6c4009
		  continue;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (wnp > npath && wnp[-1] == '/')
Packit 6c4009
	    {
Packit 6c4009
	      ++path;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      *wnp++ = *path++;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (wnp == npath || wnp[-1] != '/')
Packit 6c4009
    *wnp++ = '/';
Packit 6c4009
Packit 6c4009
  const char *trun = system_dirs;
Packit 6c4009
Packit 6c4009
  for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
Packit 6c4009
    {
Packit 6c4009
      if (wnp - npath >= system_dirs_len[idx]
Packit 6c4009
	  && memcmp (trun, npath, system_dirs_len[idx]) == 0)
Packit 6c4009
	/* Found it.  */
Packit 6c4009
	return true;
Packit 6c4009
Packit 6c4009
      trun += system_dirs_len[idx] + 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return false;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Given a substring starting at INPUT, just after the DST '$' start
Packit 6c4009
   token, determine if INPUT contains DST token REF, following the
Packit 6c4009
   ELF gABI rules for DSTs:
Packit 6c4009
Packit 6c4009
   * Longest possible sequence using the rules (greedy).
Packit 6c4009
Packit 6c4009
   * Must start with a $ (enforced by caller).
Packit 6c4009
Packit 6c4009
   * Must follow $ with one underscore or ASCII [A-Za-z] (caller
Packit 6c4009
     follows these rules for REF) or '{' (start curly quoted name).
Packit 6c4009
Packit 6c4009
   * Must follow first two characters with zero or more [A-Za-z0-9_]
Packit 6c4009
     (enforced by caller) or '}' (end curly quoted name).
Packit 6c4009
Packit 6c4009
   If the sequence is a DST matching REF then the length of the DST
Packit 6c4009
   (excluding the $ sign but including curly braces, if any) is
Packit 6c4009
   returned, otherwise 0.  */
Packit 6c4009
static size_t
Packit 6c4009
is_dst (const char *input, const char *ref)
Packit 6c4009
{
Packit 6c4009
  bool is_curly = false;
Packit 6c4009
Packit 6c4009
  /* Is a ${...} input sequence?  */
Packit 6c4009
  if (input[0] == '{')
Packit 6c4009
    {
Packit 6c4009
      is_curly = true;
Packit 6c4009
      ++input;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Check for matching name, following closing curly brace (if
Packit 6c4009
     required), or trailing characters which are part of an
Packit 6c4009
     identifier.  */
Packit 6c4009
  size_t rlen = strlen (ref);
Packit 6c4009
  if (strncmp (input, ref, rlen) != 0
Packit 6c4009
      || (is_curly && input[rlen] != '}')
Packit 6c4009
      || ((input[rlen] >= 'A' && input[rlen] <= 'Z')
Packit 6c4009
	  || (input[rlen] >= 'a' && input[rlen] <= 'z')
Packit 6c4009
	  || (input[rlen] >= '0' && input[rlen] <= '9')
Packit 6c4009
	  || (input[rlen] == '_')))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  if (is_curly)
Packit 6c4009
    /* Count the two curly braces.  */
Packit 6c4009
    return rlen + 2;
Packit 6c4009
  else
Packit 6c4009
    return rlen;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* INPUT should be the start of a path e.g DT_RPATH or name e.g.
Packit 6c4009
   DT_NEEDED.  The return value is the number of known DSTs found.  We
Packit 6c4009
   count all known DSTs regardless of __libc_enable_secure; the caller
Packit 6c4009
   is responsible for enforcing the security of the substitution rules
Packit 6c4009
   (usually _dl_dst_substitute).  */
Packit 6c4009
size_t
Packit 6c4009
_dl_dst_count (const char *input)
Packit 6c4009
{
Packit 6c4009
  size_t cnt = 0;
Packit 6c4009
Packit 6c4009
  input = strchr (input, '$');
Packit 6c4009
Packit 6c4009
  /* Most likely there is no DST.  */
Packit 6c4009
  if (__glibc_likely (input == NULL))
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      size_t len;
Packit 6c4009
Packit 6c4009
      ++input;
Packit 6c4009
      /* All DSTs must follow ELF gABI rules, see is_dst ().  */
Packit 6c4009
      if ((len = is_dst (input, "ORIGIN")) != 0
Packit 6c4009
	  || (len = is_dst (input, "PLATFORM")) != 0
Packit 6c4009
	  || (len = is_dst (input, "LIB")) != 0)
Packit 6c4009
	++cnt;
Packit 6c4009
Packit 6c4009
      /* There may be more than one DST in the input.  */
Packit 6c4009
      input = strchr (input + len, '$');
Packit 6c4009
    }
Packit 6c4009
  while (input != NULL);
Packit 6c4009
Packit 6c4009
  return cnt;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Process INPUT for DSTs and store in RESULT using the information
Packit 6c4009
   from link map L to resolve the DSTs. This function only handles one
Packit 6c4009
   path at a time and does not handle colon-separated path lists (see
Packit 6c4009
   fillin_rpath ()).  Lastly the size of result in bytes should be at
Packit 6c4009
   least equal to the value returned by DL_DST_REQUIRED.  Note that it
Packit 6c4009
   is possible for a DT_NEEDED, DT_AUXILIARY, and DT_FILTER entries to
Packit 6c4009
   have colons, but we treat those as literal colons here, not as path
Packit 6c4009
   list delimeters.  */
Packit 6c4009
char *
Packit 6c4009
_dl_dst_substitute (struct link_map *l, const char *input, char *result)
Packit 6c4009
{
Packit 6c4009
  /* Copy character-by-character from input into the working pointer
Packit 6c4009
     looking for any DSTs.  We track the start of input and if we are
Packit 6c4009
     going to check for trusted paths, all of which are part of $ORIGIN
Packit 6c4009
     handling in SUID/SGID cases (see below).  In some cases, like when
Packit 6c4009
     a DST cannot be replaced, we may set result to an empty string and
Packit 6c4009
     return.  */
Packit 6c4009
  char *wp = result;
Packit 6c4009
  const char *start = input;
Packit 6c4009
  bool check_for_trusted = false;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_unlikely (*input == '$'))
Packit 6c4009
	{
Packit 6c4009
	  const char *repl = NULL;
Packit 6c4009
	  size_t len;
Packit 6c4009
Packit 6c4009
	  ++input;
Packit 6c4009
	  if ((len = is_dst (input, "ORIGIN")) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* For SUID/GUID programs we normally ignore the path with
Packit 6c4009
		 $ORIGIN in DT_RUNPATH, or DT_RPATH.  However, there is
Packit 6c4009
		 one exception to this rule, and it is:
Packit 6c4009
Packit 6c4009
		   * $ORIGIN appears as the first path element, and is
Packit 6c4009
		     the only string in the path or is immediately
Packit 6c4009
		     followed by a path separator and the rest of the
Packit 6c4009
		     path,
Packit 6c4009
Packit 6c4009
		   and ...
Packit 6c4009
Packit 6c4009
		   * The path is rooted in a trusted directory.
Packit 6c4009
Packit 6c4009
		 This exception allows such programs to reference
Packit 6c4009
		 shared libraries in subdirectories of trusted
Packit 6c4009
		 directories.  The use case is one of general
Packit 6c4009
		 organization and deployment flexibility.
Packit 6c4009
		 Trusted directories are usually such paths as "/lib64"
Packit 6c4009
		 or "/usr/lib64", and the usual RPATHs take the form of
Packit 6c4009
		 [$ORIGIN/../$LIB/somedir].  */
Packit 6c4009
	      if (__glibc_unlikely (__libc_enable_secure)
Packit 6c4009
		  && !(input == start + 1
Packit 6c4009
		       && (input[len] == '\0' || input[len] == '/')))
Packit 6c4009
		repl = (const char *) -1;
Packit 6c4009
	      else
Packit 6c4009
	        repl = l->l_origin;
Packit 6c4009
Packit 6c4009
	      check_for_trusted = (__libc_enable_secure
Packit 6c4009
				   && l->l_type == lt_executable);
Packit 6c4009
	    }
Packit 6c4009
	  else if ((len = is_dst (input, "PLATFORM")) != 0)
Packit 6c4009
	    repl = GLRO(dl_platform);
Packit 6c4009
	  else if ((len = is_dst (input, "LIB")) != 0)
Packit 6c4009
	    repl = DL_DST_LIB;
Packit 6c4009
Packit 6c4009
	  if (repl != NULL && repl != (const char *) -1)
Packit 6c4009
	    {
Packit 6c4009
	      wp = __stpcpy (wp, repl);
Packit 6c4009
	      input += len;
Packit 6c4009
	    }
Packit 6c4009
	  else if (len != 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* We found a valid DST that we know about, but we could
Packit 6c4009
	         not find a replacement value for it, therefore we
Packit 6c4009
		 cannot use this path and discard it.  */
Packit 6c4009
	      *result = '\0';
Packit 6c4009
	      return result;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    /* No DST we recognize.  */
Packit 6c4009
	    *wp++ = '$';
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  *wp++ = *input++;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  while (*input != '\0');
Packit 6c4009
Packit 6c4009
  /* In SUID/SGID programs, after $ORIGIN expansion the normalized
Packit 6c4009
     path must be rooted in one of the trusted directories.  The $LIB
Packit 6c4009
     and $PLATFORM DST cannot in any way be manipulated by the caller
Packit 6c4009
     because they are fixed values that are set by the dynamic loader
Packit 6c4009
     and therefore any paths using just $LIB or $PLATFORM need not be
Packit 6c4009
     checked for trust, the authors of the binaries themselves are
Packit 6c4009
     trusted to have designed this correctly.  Only $ORIGIN is tested in
Packit 6c4009
     this way because it may be manipulated in some ways with hard
Packit 6c4009
     links.  */
Packit 6c4009
  if (__glibc_unlikely (check_for_trusted)
Packit 6c4009
      && !is_trusted_path_normalize (result, wp - result))
Packit 6c4009
    {
Packit 6c4009
      *result = '\0';
Packit 6c4009
      return result;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *wp = '\0';
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return a malloc allocated copy of INPUT with all recognized DSTs
Packit 6c4009
   replaced. On some platforms it might not be possible to determine the
Packit 6c4009
   path from which the object belonging to the map is loaded.  In this
Packit 6c4009
   case the path containing the DST is left out.  On error NULL
Packit 6c4009
   is returned.  */
Packit 6c4009
static char *
Packit 6c4009
expand_dynamic_string_token (struct link_map *l, const char *input)
Packit 6c4009
{
Packit 6c4009
  /* We make two runs over the string.  First we determine how large the
Packit 6c4009
     resulting string is and then we copy it over.  Since this is no
Packit 6c4009
     frequently executed operation we are looking here not for performance
Packit 6c4009
     but rather for code size.  */
Packit 6c4009
  size_t cnt;
Packit 6c4009
  size_t total;
Packit 6c4009
  char *result;
Packit 6c4009
Packit 6c4009
  /* Determine the number of DSTs.  */
Packit 6c4009
  cnt = _dl_dst_count (input);
Packit 6c4009
Packit 6c4009
  /* If we do not have to replace anything simply copy the string.  */
Packit 6c4009
  if (__glibc_likely (cnt == 0))
Packit 6c4009
    return __strdup (input);
Packit 6c4009
Packit 6c4009
  /* Determine the length of the substituted string.  */
Packit 6c4009
  total = DL_DST_REQUIRED (l, input, strlen (input), cnt);
Packit 6c4009
Packit 6c4009
  /* Allocate the necessary memory.  */
Packit 6c4009
  result = (char *) malloc (total + 1);
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  return _dl_dst_substitute (l, input, result);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Add `name' to the list of names for a particular shared object.
Packit 6c4009
   `name' is expected to have been allocated with malloc and will
Packit 6c4009
   be freed if the shared object already has this name.
Packit 6c4009
   Returns false if the object already had this name.  */
Packit 6c4009
static void
Packit 6c4009
add_name_to_object (struct link_map *l, const char *name)
Packit 6c4009
{
Packit 6c4009
  struct libname_list *lnp, *lastp;
Packit 6c4009
  struct libname_list *newname;
Packit 6c4009
  size_t name_len;
Packit 6c4009
Packit 6c4009
  lastp = NULL;
Packit 6c4009
  for (lnp = l->l_libname; lnp != NULL; lastp = lnp, lnp = lnp->next)
Packit 6c4009
    if (strcmp (name, lnp->name) == 0)
Packit 6c4009
      return;
Packit 6c4009
Packit 6c4009
  name_len = strlen (name) + 1;
Packit 6c4009
  newname = (struct libname_list *) malloc (sizeof *newname + name_len);
Packit 6c4009
  if (newname == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* No more memory.  */
Packit 6c4009
      _dl_signal_error (ENOMEM, name, NULL, N_("cannot allocate name record"));
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  /* The object should have a libname set from _dl_new_object.  */
Packit 6c4009
  assert (lastp != NULL);
Packit 6c4009
Packit 6c4009
  newname->name = memcpy (newname + 1, name, name_len);
Packit 6c4009
  newname->next = NULL;
Packit 6c4009
  newname->dont_free = 0;
Packit 6c4009
  lastp->next = newname;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Standard search directories.  */
Packit 6c4009
static struct r_search_path_struct rtld_search_dirs attribute_relro;
Packit 6c4009
Packit 6c4009
static size_t max_dirnamelen;
Packit 6c4009
Packit 6c4009
static struct r_search_path_elem **
Packit 6c4009
fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
Packit 6c4009
	      const char *what, const char *where, struct link_map *l)
Packit 6c4009
{
Packit 6c4009
  char *cp;
Packit 6c4009
  size_t nelems = 0;
Packit 6c4009
Packit 6c4009
  while ((cp = __strsep (&rpath, sep)) != NULL)
Packit 6c4009
    {
Packit 6c4009
      struct r_search_path_elem *dirp;
Packit 6c4009
      char *to_free = NULL;
Packit 6c4009
      size_t len = 0;
Packit 6c4009
Packit 6c4009
      /* `strsep' can pass an empty string.  */
Packit 6c4009
      if (*cp != '\0')
Packit 6c4009
	{
Packit 6c4009
	  to_free = cp = expand_dynamic_string_token (l, cp);
Packit 6c4009
Packit 6c4009
	  /* expand_dynamic_string_token can return NULL in case of empty
Packit 6c4009
	     path or memory allocation failure.  */
Packit 6c4009
	  if (cp == NULL)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  /* Compute the length after dynamic string token expansion and
Packit 6c4009
	     ignore empty paths.  */
Packit 6c4009
	  len = strlen (cp);
Packit 6c4009
	  if (len == 0)
Packit 6c4009
	    {
Packit 6c4009
	      free (to_free);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Remove trailing slashes (except for "/").  */
Packit 6c4009
	  while (len > 1 && cp[len - 1] == '/')
Packit 6c4009
	    --len;
Packit 6c4009
Packit 6c4009
	  /* Now add one if there is none so far.  */
Packit 6c4009
	  if (len > 0 && cp[len - 1] != '/')
Packit 6c4009
	    cp[len++] = '/';
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* See if this directory is already known.  */
Packit 6c4009
      for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
Packit 6c4009
	if (dirp->dirnamelen == len && memcmp (cp, dirp->dirname, len) == 0)
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
      if (dirp != NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* It is available, see whether it's on our own list.  */
Packit 6c4009
	  size_t cnt;
Packit 6c4009
	  for (cnt = 0; cnt < nelems; ++cnt)
Packit 6c4009
	    if (result[cnt] == dirp)
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	  if (cnt == nelems)
Packit 6c4009
	    result[nelems++] = dirp;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  size_t cnt;
Packit 6c4009
	  enum r_dir_status init_val;
Packit 6c4009
	  size_t where_len = where ? strlen (where) + 1 : 0;
Packit 6c4009
Packit 6c4009
	  /* It's a new directory.  Create an entry and add it.  */
Packit 6c4009
	  dirp = (struct r_search_path_elem *)
Packit 6c4009
	    malloc (sizeof (*dirp) + ncapstr * sizeof (enum r_dir_status)
Packit 6c4009
		    + where_len + len + 1);
Packit 6c4009
	  if (dirp == NULL)
Packit 6c4009
	    _dl_signal_error (ENOMEM, NULL, NULL,
Packit 6c4009
			      N_("cannot create cache for search path"));
Packit 6c4009
Packit 6c4009
	  dirp->dirname = ((char *) dirp + sizeof (*dirp)
Packit 6c4009
			   + ncapstr * sizeof (enum r_dir_status));
Packit 6c4009
	  *((char *) __mempcpy ((char *) dirp->dirname, cp, len)) = '\0';
Packit 6c4009
	  dirp->dirnamelen = len;
Packit 6c4009
Packit 6c4009
	  if (len > max_dirnamelen)
Packit 6c4009
	    max_dirnamelen = len;
Packit 6c4009
Packit 6c4009
	  /* We have to make sure all the relative directories are
Packit 6c4009
	     never ignored.  The current directory might change and
Packit 6c4009
	     all our saved information would be void.  */
Packit 6c4009
	  init_val = cp[0] != '/' ? existing : unknown;
Packit 6c4009
	  for (cnt = 0; cnt < ncapstr; ++cnt)
Packit 6c4009
	    dirp->status[cnt] = init_val;
Packit 6c4009
Packit 6c4009
	  dirp->what = what;
Packit 6c4009
	  if (__glibc_likely (where != NULL))
Packit 6c4009
	    dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1
Packit 6c4009
				  + (ncapstr * sizeof (enum r_dir_status)),
Packit 6c4009
				  where, where_len);
Packit 6c4009
	  else
Packit 6c4009
	    dirp->where = NULL;
Packit 6c4009
Packit 6c4009
	  dirp->next = GL(dl_all_dirs);
Packit 6c4009
	  GL(dl_all_dirs) = dirp;
Packit 6c4009
Packit 6c4009
	  /* Put it in the result array.  */
Packit 6c4009
	  result[nelems++] = dirp;
Packit 6c4009
	}
Packit 6c4009
      free (to_free);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Terminate the array.  */
Packit 6c4009
  result[nelems] = NULL;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static bool
Packit 6c4009
decompose_rpath (struct r_search_path_struct *sps,
Packit 6c4009
		 const char *rpath, struct link_map *l, const char *what)
Packit 6c4009
{
Packit 6c4009
  /* Make a copy we can work with.  */
Packit 6c4009
  const char *where = l->l_name;
Packit 6c4009
  char *cp;
Packit 6c4009
  struct r_search_path_elem **result;
Packit 6c4009
  size_t nelems;
Packit 6c4009
  /* Initialize to please the compiler.  */
Packit 6c4009
  const char *errstring = NULL;
Packit 6c4009
Packit 6c4009
  /* First see whether we must forget the RUNPATH and RPATH from this
Packit 6c4009
     object.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_inhibit_rpath) != NULL)
Packit 6c4009
      && !__libc_enable_secure)
Packit 6c4009
    {
Packit 6c4009
      const char *inhp = GLRO(dl_inhibit_rpath);
Packit 6c4009
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  const char *wp = where;
Packit 6c4009
Packit 6c4009
	  while (*inhp == *wp && *wp != '\0')
Packit 6c4009
	    {
Packit 6c4009
	      ++inhp;
Packit 6c4009
	      ++wp;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (*wp == '\0' && (*inhp == '\0' || *inhp == ':'))
Packit 6c4009
	    {
Packit 6c4009
	      /* This object is on the list of objects for which the
Packit 6c4009
		 RUNPATH and RPATH must not be used.  */
Packit 6c4009
	      sps->dirs = (void *) -1;
Packit 6c4009
	      return false;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  while (*inhp != '\0')
Packit 6c4009
	    if (*inhp++ == ':')
Packit 6c4009
	      break;
Packit 6c4009
	}
Packit 6c4009
      while (*inhp != '\0');
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Ignore empty rpaths.  */
Packit 6c4009
  if (*rpath == '\0')
Packit 6c4009
    {
Packit 6c4009
      sps->dirs = (struct r_search_path_elem **) -1;
Packit 6c4009
      return false;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Make a writable copy.  */
Packit 6c4009
  char *copy = __strdup (rpath);
Packit 6c4009
  if (copy == NULL)
Packit 6c4009
    {
Packit 6c4009
      errstring = N_("cannot create RUNPATH/RPATH copy");
Packit 6c4009
      goto signal_error;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Count the number of necessary elements in the result array.  */
Packit 6c4009
  nelems = 0;
Packit 6c4009
  for (cp = copy; *cp != '\0'; ++cp)
Packit 6c4009
    if (*cp == ':')
Packit 6c4009
      ++nelems;
Packit 6c4009
Packit 6c4009
  /* Allocate room for the result.  NELEMS + 1 is an upper limit for the
Packit 6c4009
     number of necessary entries.  */
Packit 6c4009
  result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1)
Packit 6c4009
						  * sizeof (*result));
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    {
Packit 6c4009
      free (copy);
Packit 6c4009
      errstring = N_("cannot create cache for search path");
Packit 6c4009
    signal_error:
Packit 6c4009
      _dl_signal_error (ENOMEM, NULL, NULL, errstring);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fillin_rpath (copy, result, ":", what, where, l);
Packit 6c4009
Packit 6c4009
  /* Free the copied RPATH string.  `fillin_rpath' make own copies if
Packit 6c4009
     necessary.  */
Packit 6c4009
  free (copy);
Packit 6c4009
Packit 6c4009
  /* There is no path after expansion.  */
Packit 6c4009
  if (result[0] == NULL)
Packit 6c4009
    {
Packit 6c4009
      free (result);
Packit 6c4009
      sps->dirs = (struct r_search_path_elem **) -1;
Packit 6c4009
      return false;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  sps->dirs = result;
Packit 6c4009
  /* The caller will change this value if we haven't used a real malloc.  */
Packit 6c4009
  sps->malloced = 1;
Packit 6c4009
  return true;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Make sure cached path information is stored in *SP
Packit 6c4009
   and return true if there are any paths to search there.  */
Packit 6c4009
static bool
Packit 6c4009
cache_rpath (struct link_map *l,
Packit 6c4009
	     struct r_search_path_struct *sp,
Packit 6c4009
	     int tag,
Packit 6c4009
	     const char *what)
Packit 6c4009
{
Packit 6c4009
  if (sp->dirs == (void *) -1)
Packit 6c4009
    return false;
Packit 6c4009
Packit 6c4009
  if (sp->dirs != NULL)
Packit 6c4009
    return true;
Packit 6c4009
Packit 6c4009
  if (l->l_info[tag] == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* There is no path.  */
Packit 6c4009
      sp->dirs = (void *) -1;
Packit 6c4009
      return false;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Make sure the cache information is available.  */
Packit 6c4009
  return decompose_rpath (sp, (const char *) (D_PTR (l, l_info[DT_STRTAB])
Packit 6c4009
					      + l->l_info[tag]->d_un.d_val),
Packit 6c4009
			  l, what);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_init_paths (const char *llp)
Packit 6c4009
{
Packit 6c4009
  size_t idx;
Packit 6c4009
  const char *strp;
Packit 6c4009
  struct r_search_path_elem *pelem, **aelem;
Packit 6c4009
  size_t round_size;
Packit 6c4009
  struct link_map __attribute__ ((unused)) *l = NULL;
Packit 6c4009
  /* Initialize to please the compiler.  */
Packit 6c4009
  const char *errstring = NULL;
Packit 6c4009
Packit 6c4009
  /* Fill in the information about the application's RPATH and the
Packit 6c4009
     directories addressed by the LD_LIBRARY_PATH environment variable.  */
Packit 6c4009
Packit 6c4009
  /* Get the capabilities.  */
Packit 6c4009
  capstr = _dl_important_hwcaps (GLRO(dl_platform), GLRO(dl_platformlen),
Packit 6c4009
				 &ncapstr, &max_capstrlen);
Packit 6c4009
Packit 6c4009
  /* First set up the rest of the default search directory entries.  */
Packit 6c4009
  aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **)
Packit 6c4009
    malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *));
Packit 6c4009
  if (rtld_search_dirs.dirs == NULL)
Packit 6c4009
    {
Packit 6c4009
      errstring = N_("cannot create search path array");
Packit 6c4009
    signal_error:
Packit 6c4009
      _dl_signal_error (ENOMEM, NULL, NULL, errstring);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  round_size = ((2 * sizeof (struct r_search_path_elem) - 1
Packit 6c4009
		 + ncapstr * sizeof (enum r_dir_status))
Packit 6c4009
		/ sizeof (struct r_search_path_elem));
Packit 6c4009
Packit 6c4009
  rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
Packit 6c4009
				     * sizeof (*rtld_search_dirs.dirs[0]));
Packit 6c4009
  if (rtld_search_dirs.dirs[0] == NULL)
Packit 6c4009
    {
Packit 6c4009
      errstring = N_("cannot create cache for search path");
Packit 6c4009
      goto signal_error;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  rtld_search_dirs.malloced = 0;
Packit 6c4009
  pelem = GL(dl_all_dirs) = rtld_search_dirs.dirs[0];
Packit 6c4009
  strp = system_dirs;
Packit 6c4009
  idx = 0;
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      size_t cnt;
Packit 6c4009
Packit 6c4009
      *aelem++ = pelem;
Packit 6c4009
Packit 6c4009
      pelem->what = "system search path";
Packit 6c4009
      pelem->where = NULL;
Packit 6c4009
Packit 6c4009
      pelem->dirname = strp;
Packit 6c4009
      pelem->dirnamelen = system_dirs_len[idx];
Packit 6c4009
      strp += system_dirs_len[idx] + 1;
Packit 6c4009
Packit 6c4009
      /* System paths must be absolute.  */
Packit 6c4009
      assert (pelem->dirname[0] == '/');
Packit 6c4009
      for (cnt = 0; cnt < ncapstr; ++cnt)
Packit 6c4009
	pelem->status[cnt] = unknown;
Packit 6c4009
Packit 6c4009
      pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size));
Packit 6c4009
Packit 6c4009
      pelem += round_size;
Packit 6c4009
    }
Packit 6c4009
  while (idx < nsystem_dirs_len);
Packit 6c4009
Packit 6c4009
  max_dirnamelen = SYSTEM_DIRS_MAX_LEN;
Packit 6c4009
  *aelem = NULL;
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* This points to the map of the main object.  */
Packit 6c4009
  l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit 6c4009
  if (l != NULL)
Packit 6c4009
    {
Packit 6c4009
      assert (l->l_type != lt_loaded);
Packit 6c4009
Packit 6c4009
      if (l->l_info[DT_RUNPATH])
Packit 6c4009
	{
Packit 6c4009
	  /* Allocate room for the search path and fill in information
Packit 6c4009
	     from RUNPATH.  */
Packit 6c4009
	  decompose_rpath (&l->l_runpath_dirs,
Packit 6c4009
			   (const void *) (D_PTR (l, l_info[DT_STRTAB])
Packit 6c4009
					   + l->l_info[DT_RUNPATH]->d_un.d_val),
Packit 6c4009
			   l, "RUNPATH");
Packit 6c4009
	  /* During rtld init the memory is allocated by the stub malloc,
Packit 6c4009
	     prevent any attempt to free it by the normal malloc.  */
Packit 6c4009
	  l->l_runpath_dirs.malloced = 0;
Packit 6c4009
Packit 6c4009
	  /* The RPATH is ignored.  */
Packit 6c4009
	  l->l_rpath_dirs.dirs = (void *) -1;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  l->l_runpath_dirs.dirs = (void *) -1;
Packit 6c4009
Packit 6c4009
	  if (l->l_info[DT_RPATH])
Packit 6c4009
	    {
Packit 6c4009
	      /* Allocate room for the search path and fill in information
Packit 6c4009
		 from RPATH.  */
Packit 6c4009
	      decompose_rpath (&l->l_rpath_dirs,
Packit 6c4009
			       (const void *) (D_PTR (l, l_info[DT_STRTAB])
Packit 6c4009
					       + l->l_info[DT_RPATH]->d_un.d_val),
Packit 6c4009
			       l, "RPATH");
Packit 6c4009
	      /* During rtld init the memory is allocated by the stub
Packit 6c4009
		 malloc, prevent any attempt to free it by the normal
Packit 6c4009
		 malloc.  */
Packit 6c4009
	      l->l_rpath_dirs.malloced = 0;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    l->l_rpath_dirs.dirs = (void *) -1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#endif	/* SHARED */
Packit 6c4009
Packit 6c4009
  if (llp != NULL && *llp != '\0')
Packit 6c4009
    {
Packit 6c4009
      char *llp_tmp = strdupa (llp);
Packit 6c4009
Packit 6c4009
      /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
Packit 6c4009
	 elements it has.  */
Packit 6c4009
      size_t nllp = 1;
Packit 6c4009
      for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
Packit 6c4009
	if (*cp == ':' || *cp == ';')
Packit 6c4009
	  ++nllp;
Packit 6c4009
Packit 6c4009
      env_path_list.dirs = (struct r_search_path_elem **)
Packit 6c4009
	malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
Packit 6c4009
      if (env_path_list.dirs == NULL)
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("cannot create cache for search path");
Packit 6c4009
	  goto signal_error;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
Packit 6c4009
			   "LD_LIBRARY_PATH", NULL, l);
Packit 6c4009
Packit 6c4009
      if (env_path_list.dirs[0] == NULL)
Packit 6c4009
	{
Packit 6c4009
	  free (env_path_list.dirs);
Packit 6c4009
	  env_path_list.dirs = (void *) -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      env_path_list.malloced = 0;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    env_path_list.dirs = (void *) -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
__attribute__ ((noreturn, noinline))
Packit 6c4009
lose (int code, int fd, const char *name, char *realname, struct link_map *l,
Packit 6c4009
      const char *msg, struct r_debug *r, Lmid_t nsid)
Packit 6c4009
{
Packit 6c4009
  /* The file might already be closed.  */
Packit 6c4009
  if (fd != -1)
Packit 6c4009
    (void) __close_nocancel (fd);
Packit 6c4009
  if (l != NULL && l->l_origin != (char *) -1l)
Packit 6c4009
    free ((char *) l->l_origin);
Packit 6c4009
  free (l);
Packit 6c4009
  free (realname);
Packit 6c4009
Packit 6c4009
  if (r != NULL)
Packit 6c4009
    {
Packit 6c4009
      r->r_state = RT_CONSISTENT;
Packit 6c4009
      _dl_debug_state ();
Packit 6c4009
      LIBC_PROBE (map_failed, 2, nsid, r);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  _dl_signal_error (code, name, NULL, msg);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Map in the shared object NAME, actually located in REALNAME, and already
Packit 6c4009
   opened on FD.  */
Packit 6c4009
Packit 6c4009
#ifndef EXTERNAL_MAP_FROM_FD
Packit 6c4009
static
Packit 6c4009
#endif
Packit 6c4009
struct link_map *
Packit 6c4009
_dl_map_object_from_fd (const char *name, const char *origname, int fd,
Packit 6c4009
			struct filebuf *fbp, char *realname,
Packit 6c4009
			struct link_map *loader, int l_type, int mode,
Packit 6c4009
			void **stack_endp, Lmid_t nsid)
Packit 6c4009
{
Packit 6c4009
  struct link_map *l = NULL;
Packit 6c4009
  const ElfW(Ehdr) *header;
Packit 6c4009
  const ElfW(Phdr) *phdr;
Packit 6c4009
  const ElfW(Phdr) *ph;
Packit 6c4009
  size_t maplength;
Packit 6c4009
  int type;
Packit 6c4009
  /* Initialize to keep the compiler happy.  */
Packit 6c4009
  const char *errstring = NULL;
Packit 6c4009
  int errval = 0;
Packit 6c4009
  struct r_debug *r = _dl_debug_initialize (0, nsid);
Packit 6c4009
  bool make_consistent = false;
Packit 6c4009
Packit 6c4009
  /* Get file information.  */
Packit 6c4009
  struct r_file_id id;
Packit dfff7d
  struct stat64 st;
Packit dfff7d
  if (__glibc_unlikely (!_dl_get_file_id (fd, &id, &st)))
Packit 6c4009
    {
Packit 6c4009
      errstring = N_("cannot stat shared object");
Packit 6c4009
    call_lose_errno:
Packit 6c4009
      errval = errno;
Packit 6c4009
    call_lose:
Packit 6c4009
      lose (errval, fd, name, realname, l, errstring,
Packit 6c4009
	    make_consistent ? r : NULL, nsid);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Look again to see if the real name matched another already loaded.  */
Packit 6c4009
  for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
Packit 6c4009
    if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
Packit 6c4009
      {
Packit 6c4009
	/* The object is already loaded.
Packit 6c4009
	   Just bump its reference count and return it.  */
Packit 6c4009
	__close_nocancel (fd);
Packit 6c4009
Packit 6c4009
	/* If the name is not in the list of names for this object add
Packit 6c4009
	   it.  */
Packit 6c4009
	free (realname);
Packit 6c4009
	add_name_to_object (l, name);
Packit 6c4009
Packit 6c4009
	return l;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* When loading into a namespace other than the base one we must
Packit 6c4009
     avoid loading ld.so since there can only be one copy.  Ever.  */
Packit 6c4009
  if (__glibc_unlikely (nsid != LM_ID_BASE)
Packit 6c4009
      && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
Packit 6c4009
	  || _dl_name_match_p (name, &GL(dl_rtld_map))))
Packit 6c4009
    {
Packit 6c4009
      /* This is indeed ld.so.  Create a new link_map which refers to
Packit 6c4009
	 the real one for almost everything.  */
Packit 6c4009
      l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
Packit 6c4009
      if (l == NULL)
Packit 6c4009
	goto fail_new;
Packit 6c4009
Packit 6c4009
      /* Refer to the real descriptor.  */
Packit 6c4009
      l->l_real = &GL(dl_rtld_map);
Packit 6c4009
Packit 6c4009
      /* No need to bump the refcount of the real object, ld.so will
Packit 6c4009
	 never be unloaded.  */
Packit 6c4009
      __close_nocancel (fd);
Packit 6c4009
Packit 6c4009
      /* Add the map for the mirrored object to the object list.  */
Packit 6c4009
      _dl_add_to_namespace_list (l, nsid);
Packit 6c4009
Packit 6c4009
      return l;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (mode & RTLD_NOLOAD)
Packit 6c4009
    {
Packit 6c4009
      /* We are not supposed to load the object unless it is already
Packit 6c4009
	 loaded.  So return now.  */
Packit 6c4009
      free (realname);
Packit 6c4009
      __close_nocancel (fd);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Print debugging message.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
Packit 6c4009
    _dl_debug_printf ("file=%s [%lu];  generating link map\n", name, nsid);
Packit 6c4009
Packit 6c4009
  /* This is the ELF header.  We read it in `open_verify'.  */
Packit 6c4009
  header = (void *) fbp->buf;
Packit 6c4009
Packit 6c4009
#ifndef MAP_ANON
Packit 6c4009
# define MAP_ANON 0
Packit 6c4009
  if (_dl_zerofd == -1)
Packit 6c4009
    {
Packit 6c4009
      _dl_zerofd = _dl_sysdep_open_zero_fill ();
Packit 6c4009
      if (_dl_zerofd == -1)
Packit 6c4009
	{
Packit 6c4009
	  free (realname);
Packit 6c4009
	  __close_nocancel (fd);
Packit 6c4009
	  _dl_signal_error (errno, NULL, NULL,
Packit 6c4009
			    N_("cannot open zero fill device"));
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Signal that we are going to add new objects.  */
Packit 6c4009
  if (r->r_state == RT_CONSISTENT)
Packit 6c4009
    {
Packit 6c4009
#ifdef SHARED
Packit 6c4009
      /* Auditing checkpoint: we are going to add new objects.  */
Packit 6c4009
      if ((mode & __RTLD_AUDIT) == 0
Packit 6c4009
	  && __glibc_unlikely (GLRO(dl_naudit) > 0))
Packit 6c4009
	{
Packit 6c4009
	  struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
Packit 6c4009
	  /* Do not call the functions for any auditing object.  */
Packit 6c4009
	  if (head->l_auditing == 0)
Packit 6c4009
	    {
Packit 6c4009
	      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
		{
Packit 6c4009
		  if (afct->activity != NULL)
Packit 6c4009
		    afct->activity (&head->l_audit[cnt].cookie, LA_ACT_ADD);
Packit 6c4009
Packit 6c4009
		  afct = afct->next;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      /* Notify the debugger we have added some objects.  We need to
Packit 6c4009
	 call _dl_debug_initialize in a static program in case dynamic
Packit 6c4009
	 linking has not been used before.  */
Packit 6c4009
      r->r_state = RT_ADD;
Packit 6c4009
      _dl_debug_state ();
Packit 6c4009
      LIBC_PROBE (map_start, 2, nsid, r);
Packit 6c4009
      make_consistent = true;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    assert (r->r_state == RT_ADD);
Packit 6c4009
Packit 6c4009
  /* Enter the new object in the list of loaded objects.  */
Packit 6c4009
  l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
Packit 6c4009
  if (__glibc_unlikely (l == NULL))
Packit 6c4009
    {
Packit 6c4009
#ifdef SHARED
Packit 6c4009
    fail_new:
Packit 6c4009
#endif
Packit 6c4009
      errstring = N_("cannot create shared object descriptor");
Packit 6c4009
      goto call_lose_errno;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Extract the remaining details we need from the ELF header
Packit 6c4009
     and then read in the program header table.  */
Packit 6c4009
  l->l_entry = header->e_entry;
Packit 6c4009
  type = header->e_type;
Packit 6c4009
  l->l_phnum = header->e_phnum;
Packit 6c4009
Packit 6c4009
  maplength = header->e_phnum * sizeof (ElfW(Phdr));
Packit 6c4009
  if (header->e_phoff + maplength <= (size_t) fbp->len)
Packit 6c4009
    phdr = (void *) (fbp->buf + header->e_phoff);
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      phdr = alloca (maplength);
Packit 6c4009
      __lseek (fd, header->e_phoff, SEEK_SET);
Packit 6c4009
      if ((size_t) __read_nocancel (fd, (void *) phdr, maplength) != maplength)
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("cannot read file data");
Packit 6c4009
	  goto call_lose_errno;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
   /* On most platforms presume that PT_GNU_STACK is absent and the stack is
Packit 6c4009
    * executable.  Other platforms default to a nonexecutable stack and don't
Packit 6c4009
    * need PT_GNU_STACK to do so.  */
Packit 6c4009
   uint_fast16_t stack_flags = DEFAULT_STACK_PERMS;
Packit 6c4009
Packit 6c4009
  {
Packit 6c4009
    /* Scan the program header table, collecting its load commands.  */
Packit 6c4009
    struct loadcmd loadcmds[l->l_phnum];
Packit 6c4009
    size_t nloadcmds = 0;
Packit 6c4009
    bool has_holes = false;
Packit 6c4009
Packit 6c4009
    /* The struct is initialized to zero so this is not necessary:
Packit 6c4009
    l->l_ld = 0;
Packit 6c4009
    l->l_phdr = 0;
Packit 6c4009
    l->l_addr = 0; */
Packit 6c4009
    for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph)
Packit 6c4009
      switch (ph->p_type)
Packit 6c4009
	{
Packit 6c4009
	  /* These entries tell us where to find things once the file's
Packit 6c4009
	     segments are mapped in.  We record the addresses it says
Packit 6c4009
	     verbatim, and later correct for the run-time load address.  */
Packit 6c4009
	case PT_DYNAMIC:
Packit 6c4009
	  if (ph->p_filesz)
Packit 6c4009
	    {
Packit 6c4009
	      /* Debuginfo only files from "objcopy --only-keep-debug"
Packit 6c4009
		 contain a PT_DYNAMIC segment with p_filesz == 0.  Skip
Packit 6c4009
		 such a segment to avoid a crash later.  */
Packit 6c4009
	      l->l_ld = (void *) ph->p_vaddr;
Packit 6c4009
	      l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case PT_PHDR:
Packit 6c4009
	  l->l_phdr = (void *) ph->p_vaddr;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case PT_LOAD:
Packit 6c4009
	  /* A load command tells us to map in part of the file.
Packit 6c4009
	     We record the load commands and process them all later.  */
Packit 6c4009
	  if (__glibc_unlikely ((ph->p_align & (GLRO(dl_pagesize) - 1)) != 0))
Packit 6c4009
	    {
Packit 6c4009
	      errstring = N_("ELF load command alignment not page-aligned");
Packit 6c4009
	      goto call_lose;
Packit 6c4009
	    }
Packit 6c4009
	  if (__glibc_unlikely (((ph->p_vaddr - ph->p_offset)
Packit 6c4009
				 & (ph->p_align - 1)) != 0))
Packit 6c4009
	    {
Packit 6c4009
	      errstring
Packit 6c4009
		= N_("ELF load command address/offset not properly aligned");
Packit 6c4009
	      goto call_lose;
Packit 6c4009
	    }
Packit dfff7d
	  if (__glibc_unlikely (ph->p_offset + ph->p_filesz > st.st_size))
Packit dfff7d
	    {
Packit dfff7d
	      /* If the segment requires zeroing of part of its last
Packit dfff7d
		 page, we'll crash when accessing the unmapped page.
Packit dfff7d
		 There's still a possibility of a race, if the shared
Packit dfff7d
		 object is truncated between the fxstat above and the
Packit dfff7d
		 memset below.  */
Packit dfff7d
	      errstring = N_("ELF load command past end of file");
Packit dfff7d
	      goto call_lose;
Packit dfff7d
	    }
Packit 6c4009
Packit 6c4009
	  struct loadcmd *c = &loadcmds[nloadcmds++];
Packit 6c4009
	  c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
Packit 6c4009
	  c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
Packit 6c4009
	  c->dataend = ph->p_vaddr + ph->p_filesz;
Packit 6c4009
	  c->allocend = ph->p_vaddr + ph->p_memsz;
Packit 6c4009
	  c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
Packit 6c4009
Packit 6c4009
	  /* Determine whether there is a gap between the last segment
Packit 6c4009
	     and this one.  */
Packit 6c4009
	  if (nloadcmds > 1 && c[-1].mapend != c->mapstart)
Packit 6c4009
	    has_holes = true;
Packit 6c4009
Packit 6c4009
	  /* Optimize a common case.  */
Packit 6c4009
#if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7
Packit 6c4009
	  c->prot = (PF_TO_PROT
Packit 6c4009
		     >> ((ph->p_flags & (PF_R | PF_W | PF_X)) * 4)) & 0xf;
Packit 6c4009
#else
Packit 6c4009
	  c->prot = 0;
Packit 6c4009
	  if (ph->p_flags & PF_R)
Packit 6c4009
	    c->prot |= PROT_READ;
Packit 6c4009
	  if (ph->p_flags & PF_W)
Packit 6c4009
	    c->prot |= PROT_WRITE;
Packit 6c4009
	  if (ph->p_flags & PF_X)
Packit 6c4009
	    c->prot |= PROT_EXEC;
Packit 6c4009
#endif
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case PT_TLS:
Packit 6c4009
	  if (ph->p_memsz == 0)
Packit 6c4009
	    /* Nothing to do for an empty segment.  */
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  l->l_tls_blocksize = ph->p_memsz;
Packit 6c4009
	  l->l_tls_align = ph->p_align;
Packit 6c4009
	  if (ph->p_align == 0)
Packit 6c4009
	    l->l_tls_firstbyte_offset = 0;
Packit 6c4009
	  else
Packit 6c4009
	    l->l_tls_firstbyte_offset = ph->p_vaddr & (ph->p_align - 1);
Packit 6c4009
	  l->l_tls_initimage_size = ph->p_filesz;
Packit 6c4009
	  /* Since we don't know the load address yet only store the
Packit 6c4009
	     offset.  We will adjust it later.  */
Packit 6c4009
	  l->l_tls_initimage = (void *) ph->p_vaddr;
Packit 6c4009
Packit 6c4009
	  /* If not loading the initial set of shared libraries,
Packit 6c4009
	     check whether we should permit loading a TLS segment.  */
Packit 6c4009
	  if (__glibc_likely (l->l_type == lt_library)
Packit 6c4009
	      /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did
Packit 6c4009
		 not set up TLS data structures, so don't use them now.  */
Packit 6c4009
	      || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL))
Packit 6c4009
	    {
Packit 6c4009
	      /* Assign the next available module ID.  */
Packit 6c4009
	      l->l_tls_modid = _dl_next_tls_modid ();
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
	  /* We are loading the executable itself when the dynamic
Packit 6c4009
	     linker was executed directly.  The setup will happen
Packit 6c4009
	     later.  Otherwise, the TLS data structures are already
Packit 6c4009
	     initialized, and we assigned a TLS modid above.  */
Packit 6c4009
	  assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
Packit 6c4009
#else
Packit 6c4009
	  assert (false && "TLS not initialized in static application");
Packit 6c4009
#endif
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case PT_GNU_STACK:
Packit 6c4009
	  stack_flags = ph->p_flags;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case PT_GNU_RELRO:
Packit 6c4009
	  l->l_relro_addr = ph->p_vaddr;
Packit 6c4009
	  l->l_relro_size = ph->p_memsz;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case PT_NOTE:
Packit 6c4009
	  if (_dl_process_pt_note (l, ph, fd, fbp))
Packit 6c4009
	    {
Packit 6c4009
	      errstring = N_("cannot process note segment");
Packit 6c4009
	      goto call_lose;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    if (__glibc_unlikely (nloadcmds == 0))
Packit 6c4009
      {
Packit 6c4009
	/* This only happens for a bogus object that will be caught with
Packit 6c4009
	   another error below.  But we don't want to go through the
Packit 6c4009
	   calculations below using NLOADCMDS - 1.  */
Packit 6c4009
	errstring = N_("object file has no loadable segments");
Packit 6c4009
	goto call_lose;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    if (__glibc_unlikely (type != ET_DYN)
Packit 6c4009
	&& __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
Packit 6c4009
      {
Packit 6c4009
	/* This object is loaded at a fixed address.  This must never
Packit 6c4009
	   happen for objects loaded with dlopen.  */
Packit 6c4009
	errstring = N_("cannot dynamically load executable");
Packit 6c4009
	goto call_lose;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    /* Length of the sections to be loaded.  */
Packit 6c4009
    maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
Packit 6c4009
Packit 6c4009
    /* Now process the load commands and map segments into memory.
Packit 6c4009
       This is responsible for filling in:
Packit 6c4009
       l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
Packit 6c4009
     */
Packit 6c4009
    errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
Packit 6c4009
				  maplength, has_holes, loader);
Packit 6c4009
    if (__glibc_unlikely (errstring != NULL))
Packit 6c4009
      goto call_lose;
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  if (l->l_ld == 0)
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_unlikely (type == ET_DYN))
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("object file has no dynamic section");
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
Packit 6c4009
Packit 6c4009
  elf_get_dynamic_info (l, NULL);
Packit 6c4009
Packit 6c4009
  /* Make sure we are not dlopen'ing an object that has the
Packit 6c4009
     DF_1_NOOPEN flag set.  */
Packit 6c4009
  if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
Packit 6c4009
      && (mode & __RTLD_DLOPEN))
Packit 6c4009
    {
Packit 6c4009
      /* We are not supposed to load this object.  Free all resources.  */
Packit 6c4009
      _dl_unmap_segments (l);
Packit 6c4009
Packit 6c4009
      if (!l->l_libname->dont_free)
Packit 6c4009
	free (l->l_libname);
Packit 6c4009
Packit 6c4009
      if (l->l_phdr_allocated)
Packit 6c4009
	free ((void *) l->l_phdr);
Packit 6c4009
Packit 6c4009
      errstring = N_("shared object cannot be dlopen()ed");
Packit 6c4009
      goto call_lose;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (l->l_phdr == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* The program header is not contained in any of the segments.
Packit 6c4009
	 We have to allocate memory ourself and copy it over from out
Packit 6c4009
	 temporary place.  */
Packit 6c4009
      ElfW(Phdr) *newp = (ElfW(Phdr) *) malloc (header->e_phnum
Packit 6c4009
						* sizeof (ElfW(Phdr)));
Packit 6c4009
      if (newp == NULL)
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("cannot allocate memory for program header");
Packit 6c4009
	  goto call_lose_errno;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      l->l_phdr = memcpy (newp, phdr,
Packit 6c4009
			  (header->e_phnum * sizeof (ElfW(Phdr))));
Packit 6c4009
      l->l_phdr_allocated = 1;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    /* Adjust the PT_PHDR value by the runtime load address.  */
Packit 6c4009
    l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
Packit 6c4009
    {
Packit 6c4009
      /* The stack is presently not executable, but this module
Packit 6c4009
	 requires that it be executable.  We must change the
Packit 6c4009
	 protection of the variable which contains the flags used in
Packit 6c4009
	 the mprotect calls.  */
Packit 6c4009
#ifdef SHARED
Packit 6c4009
      if ((mode & (__RTLD_DLOPEN | __RTLD_AUDIT)) == __RTLD_DLOPEN)
Packit 6c4009
	{
Packit 6c4009
	  const uintptr_t p = (uintptr_t) &__stack_prot & -GLRO(dl_pagesize);
Packit 6c4009
	  const size_t s = (uintptr_t) (&__stack_prot + 1) - p;
Packit 6c4009
Packit 6c4009
	  struct link_map *const m = &GL(dl_rtld_map);
Packit 6c4009
	  const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
Packit 6c4009
					+ m->l_relro_size)
Packit 6c4009
				       & -GLRO(dl_pagesize));
Packit 6c4009
	  if (__glibc_likely (p + s <= relro_end))
Packit 6c4009
	    {
Packit 6c4009
	      /* The variable lies in the region protected by RELRO.  */
Packit 6c4009
	      if (__mprotect ((void *) p, s, PROT_READ|PROT_WRITE) < 0)
Packit 6c4009
		{
Packit 6c4009
		  errstring = N_("cannot change memory protections");
Packit 6c4009
		  goto call_lose_errno;
Packit 6c4009
		}
Packit 6c4009
	      __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
Packit 6c4009
	      __mprotect ((void *) p, s, PROT_READ);
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
#endif
Packit 6c4009
	__stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
Packit 6c4009
Packit 6c4009
#ifdef check_consistency
Packit 6c4009
      check_consistency ();
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      errval = (*GL(dl_make_stack_executable_hook)) (stack_endp);
Packit 6c4009
      if (errval)
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("\
Packit 6c4009
cannot enable executable stack as shared object requires");
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Adjust the address of the TLS initialization image.  */
Packit 6c4009
  if (l->l_tls_initimage != NULL)
Packit 6c4009
    l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
Packit 6c4009
Packit 6c4009
  /* We are done mapping in the file.  We no longer need the descriptor.  */
Packit 6c4009
  if (__glibc_unlikely (__close_nocancel (fd) != 0))
Packit 6c4009
    {
Packit 6c4009
      errstring = N_("cannot close file descriptor");
Packit 6c4009
      goto call_lose_errno;
Packit 6c4009
    }
Packit 6c4009
  /* Signal that we closed the file.  */
Packit 6c4009
  fd = -1;
Packit 6c4009
Packit 6c4009
  /* If this is ET_EXEC, we should have loaded it as lt_executable.  */
Packit 6c4009
  assert (type != ET_EXEC || l->l_type == lt_executable);
Packit 6c4009
Packit 6c4009
  l->l_entry += l->l_addr;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
Packit 6c4009
    _dl_debug_printf ("\
Packit 6c4009
  dynamic: 0x%0*lx  base: 0x%0*lx   size: 0x%0*Zx\n\
Packit 6c4009
    entry: 0x%0*lx  phdr: 0x%0*lx  phnum:   %*u\n\n",
Packit 6c4009
			   (int) sizeof (void *) * 2,
Packit 6c4009
			   (unsigned long int) l->l_ld,
Packit 6c4009
			   (int) sizeof (void *) * 2,
Packit 6c4009
			   (unsigned long int) l->l_addr,
Packit 6c4009
			   (int) sizeof (void *) * 2, maplength,
Packit 6c4009
			   (int) sizeof (void *) * 2,
Packit 6c4009
			   (unsigned long int) l->l_entry,
Packit 6c4009
			   (int) sizeof (void *) * 2,
Packit 6c4009
			   (unsigned long int) l->l_phdr,
Packit 6c4009
			   (int) sizeof (void *) * 2, l->l_phnum);
Packit 6c4009
Packit 6c4009
  /* Set up the symbol hash table.  */
Packit 6c4009
  _dl_setup_hash (l);
Packit 6c4009
Packit 6c4009
  /* If this object has DT_SYMBOLIC set modify now its scope.  We don't
Packit 6c4009
     have to do this for the main map.  */
Packit 6c4009
  if ((mode & RTLD_DEEPBIND) == 0
Packit 6c4009
      && __glibc_unlikely (l->l_info[DT_SYMBOLIC] != NULL)
Packit 6c4009
      && &l->l_searchlist != l->l_scope[0])
Packit 6c4009
    {
Packit 6c4009
      /* Create an appropriate searchlist.  It contains only this map.
Packit 6c4009
	 This is the definition of DT_SYMBOLIC in SysVr4.  */
Packit 6c4009
      l->l_symbolic_searchlist.r_list[0] = l;
Packit 6c4009
      l->l_symbolic_searchlist.r_nlist = 1;
Packit 6c4009
Packit 6c4009
      /* Now move the existing entries one back.  */
Packit 6c4009
      memmove (&l->l_scope[1], &l->l_scope[0],
Packit 6c4009
	       (l->l_scope_max - 1) * sizeof (l->l_scope[0]));
Packit 6c4009
Packit 6c4009
      /* Now add the new entry.  */
Packit 6c4009
      l->l_scope[0] = &l->l_symbolic_searchlist;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Remember whether this object must be initialized first.  */
Packit 6c4009
  if (l->l_flags_1 & DF_1_INITFIRST)
Packit 6c4009
    GL(dl_initfirst) = l;
Packit 6c4009
Packit 6c4009
  /* Finally the file information.  */
Packit 6c4009
  l->l_file_id = id;
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* When auditing is used the recorded names might not include the
Packit 6c4009
     name by which the DSO is actually known.  Add that as well.  */
Packit 6c4009
  if (__glibc_unlikely (origname != NULL))
Packit 6c4009
    add_name_to_object (l, origname);
Packit 6c4009
#else
Packit 6c4009
  /* Audit modules only exist when linking is dynamic so ORIGNAME
Packit 6c4009
     cannot be non-NULL.  */
Packit 6c4009
  assert (origname == NULL);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* When we profile the SONAME might be needed for something else but
Packit 6c4009
     loading.  Add it right away.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_profile) != NULL)
Packit 6c4009
      && l->l_info[DT_SONAME] != NULL)
Packit 6c4009
    add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
Packit 6c4009
			    + l->l_info[DT_SONAME]->d_un.d_val));
Packit 6c4009
Packit 6c4009
#ifdef DL_AFTER_LOAD
Packit 6c4009
  DL_AFTER_LOAD (l);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Now that the object is fully initialized add it to the object list.  */
Packit 6c4009
  _dl_add_to_namespace_list (l, nsid);
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Auditing checkpoint: we have a new object.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_naudit) > 0)
Packit 6c4009
      && !GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
Packit 6c4009
    {
Packit 6c4009
      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (afct->objopen != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      l->l_audit[cnt].bindflags
Packit 6c4009
		= afct->objopen (l, nsid, &l->l_audit[cnt].cookie);
Packit 6c4009
Packit 6c4009
	      l->l_audit_any_plt |= l->l_audit[cnt].bindflags != 0;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  afct = afct->next;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  return l;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Print search path.  */
Packit 6c4009
static void
Packit 6c4009
print_search_path (struct r_search_path_elem **list,
Packit 6c4009
		   const char *what, const char *name)
Packit 6c4009
{
Packit 6c4009
  char buf[max_dirnamelen + max_capstrlen];
Packit 6c4009
  int first = 1;
Packit 6c4009
Packit 6c4009
  _dl_debug_printf (" search path=");
Packit 6c4009
Packit 6c4009
  while (*list != NULL && (*list)->what == what) /* Yes, ==.  */
Packit 6c4009
    {
Packit 6c4009
      char *endp = __mempcpy (buf, (*list)->dirname, (*list)->dirnamelen);
Packit 6c4009
      size_t cnt;
Packit 6c4009
Packit 6c4009
      for (cnt = 0; cnt < ncapstr; ++cnt)
Packit 6c4009
	if ((*list)->status[cnt] != nonexisting)
Packit 6c4009
	  {
Packit 6c4009
	    char *cp = __mempcpy (endp, capstr[cnt].str, capstr[cnt].len);
Packit 6c4009
	    if (cp == buf || (cp == buf + 1 && buf[0] == '/'))
Packit 6c4009
	      cp[0] = '\0';
Packit 6c4009
	    else
Packit 6c4009
	      cp[-1] = '\0';
Packit 6c4009
Packit 6c4009
	    _dl_debug_printf_c (first ? "%s" : ":%s", buf);
Packit 6c4009
	    first = 0;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
      ++list;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (name != NULL)
Packit 6c4009
    _dl_debug_printf_c ("\t\t(%s from file %s)\n", what,
Packit 6c4009
			DSO_FILENAME (name));
Packit 6c4009
  else
Packit 6c4009
    _dl_debug_printf_c ("\t\t(%s)\n", what);
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Open a file and verify it is an ELF file for this architecture.  We
Packit 6c4009
   ignore only ELF files for other architectures.  Non-ELF files and
Packit 6c4009
   ELF files with different header information cause fatal errors since
Packit 6c4009
   this could mean there is something wrong in the installation and the
Packit 6c4009
   user might want to know about this.
Packit 6c4009
Packit 6c4009
   If FD is not -1, then the file is already open and FD refers to it.
Packit 6c4009
   In that case, FD is consumed for both successful and error returns.  */
Packit 6c4009
static int
Packit 6c4009
open_verify (const char *name, int fd,
Packit 6c4009
             struct filebuf *fbp, struct link_map *loader,
Packit 6c4009
	     int whatcode, int mode, bool *found_other_class, bool free_name)
Packit 6c4009
{
Packit 6c4009
  /* This is the expected ELF header.  */
Packit 6c4009
#define ELF32_CLASS ELFCLASS32
Packit 6c4009
#define ELF64_CLASS ELFCLASS64
Packit 6c4009
#ifndef VALID_ELF_HEADER
Packit 6c4009
# define VALID_ELF_HEADER(hdr,exp,size)	(memcmp (hdr, exp, size) == 0)
Packit 6c4009
# define VALID_ELF_OSABI(osabi)		(osabi == ELFOSABI_SYSV)
Packit 6c4009
# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0)
Packit 6c4009
#elif defined MORE_ELF_HEADER_DATA
Packit 6c4009
  MORE_ELF_HEADER_DATA;
Packit 6c4009
#endif
Packit 6c4009
  static const unsigned char expected[EI_NIDENT] =
Packit 6c4009
  {
Packit 6c4009
    [EI_MAG0] = ELFMAG0,
Packit 6c4009
    [EI_MAG1] = ELFMAG1,
Packit 6c4009
    [EI_MAG2] = ELFMAG2,
Packit 6c4009
    [EI_MAG3] = ELFMAG3,
Packit 6c4009
    [EI_CLASS] = ELFW(CLASS),
Packit 6c4009
    [EI_DATA] = byteorder,
Packit 6c4009
    [EI_VERSION] = EV_CURRENT,
Packit 6c4009
    [EI_OSABI] = ELFOSABI_SYSV,
Packit 6c4009
    [EI_ABIVERSION] = 0
Packit 6c4009
  };
Packit 6c4009
  static const struct
Packit 6c4009
  {
Packit 6c4009
    ElfW(Word) vendorlen;
Packit 6c4009
    ElfW(Word) datalen;
Packit 6c4009
    ElfW(Word) type;
Packit 6c4009
    char vendor[4];
Packit 6c4009
  } expected_note = { 4, 16, 1, "GNU" };
Packit 6c4009
  /* Initialize it to make the compiler happy.  */
Packit 6c4009
  const char *errstring = NULL;
Packit 6c4009
  int errval = 0;
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Give the auditing libraries a chance.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0
Packit 6c4009
      && loader->l_auditing == 0)
Packit 6c4009
    {
Packit 6c4009
      const char *original_name = name;
Packit 6c4009
      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (afct->objsearch != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
Packit 6c4009
				      whatcode);
Packit 6c4009
	      if (name == NULL)
Packit 6c4009
		/* Ignore the path.  */
Packit 6c4009
		return -1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  afct = afct->next;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (fd != -1 && name != original_name && strcmp (name, original_name))
Packit 6c4009
        {
Packit 6c4009
          /* An audit library changed what we're supposed to open,
Packit 6c4009
             so FD no longer matches it.  */
Packit 6c4009
          __close_nocancel (fd);
Packit 6c4009
          fd = -1;
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    /* Open the file.  We always open files read-only.  */
Packit 6c4009
    fd = __open64_nocancel (name, O_RDONLY | O_CLOEXEC);
Packit 6c4009
Packit 6c4009
  if (fd != -1)
Packit 6c4009
    {
Packit 6c4009
      ElfW(Ehdr) *ehdr;
Packit 6c4009
      ElfW(Phdr) *phdr, *ph;
Packit 6c4009
      ElfW(Word) *abi_note;
Packit 6c4009
      ElfW(Word) *abi_note_malloced = NULL;
Packit 6c4009
      unsigned int osversion;
Packit 6c4009
      size_t maplength;
Packit 6c4009
Packit 6c4009
      /* We successfully opened the file.  Now verify it is a file
Packit 6c4009
	 we can use.  */
Packit 6c4009
      __set_errno (0);
Packit 6c4009
      fbp->len = 0;
Packit 6c4009
      assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
Packit 6c4009
      /* Read in the header.  */
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  ssize_t retlen = __read_nocancel (fd, fbp->buf + fbp->len,
Packit 6c4009
					    sizeof (fbp->buf) - fbp->len);
Packit 6c4009
	  if (retlen <= 0)
Packit 6c4009
	    break;
Packit 6c4009
	  fbp->len += retlen;
Packit 6c4009
	}
Packit 6c4009
      while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr))));
Packit 6c4009
Packit 6c4009
      /* This is where the ELF header is loaded.  */
Packit 6c4009
      ehdr = (ElfW(Ehdr) *) fbp->buf;
Packit 6c4009
Packit 6c4009
      /* Now run the tests.  */
Packit 6c4009
      if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr))))
Packit 6c4009
	{
Packit 6c4009
	  errval = errno;
Packit 6c4009
	  errstring = (errval == 0
Packit 6c4009
		       ? N_("file too short") : N_("cannot read file data"));
Packit 6c4009
	call_lose:
Packit 6c4009
	  if (free_name)
Packit 6c4009
	    {
Packit 6c4009
	      char *realname = (char *) name;
Packit 6c4009
	      name = strdupa (realname);
Packit 6c4009
	      free (realname);
Packit 6c4009
	    }
Packit 6c4009
	  lose (errval, fd, name, NULL, NULL, errstring, NULL, 0);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* See whether the ELF header is what we expect.  */
Packit 6c4009
      if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected,
Packit 6c4009
						EI_ABIVERSION)
Packit 6c4009
			    || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
Packit 6c4009
						      ehdr->e_ident[EI_ABIVERSION])
Packit 6c4009
			    || memcmp (&ehdr->e_ident[EI_PAD],
Packit 6c4009
				       &expected[EI_PAD],
Packit 6c4009
				       EI_NIDENT - EI_PAD) != 0))
Packit 6c4009
	{
Packit 6c4009
	  /* Something is wrong.  */
Packit 6c4009
	  const Elf32_Word *magp = (const void *) ehdr->e_ident;
Packit 6c4009
	  if (*magp !=
Packit 6c4009
#if BYTE_ORDER == LITTLE_ENDIAN
Packit 6c4009
	      ((ELFMAG0 << (EI_MAG0 * 8)) |
Packit 6c4009
	       (ELFMAG1 << (EI_MAG1 * 8)) |
Packit 6c4009
	       (ELFMAG2 << (EI_MAG2 * 8)) |
Packit 6c4009
	       (ELFMAG3 << (EI_MAG3 * 8)))
Packit 6c4009
#else
Packit 6c4009
	      ((ELFMAG0 << (EI_MAG3 * 8)) |
Packit 6c4009
	       (ELFMAG1 << (EI_MAG2 * 8)) |
Packit 6c4009
	       (ELFMAG2 << (EI_MAG1 * 8)) |
Packit 6c4009
	       (ELFMAG3 << (EI_MAG0 * 8)))
Packit 6c4009
#endif
Packit 6c4009
	      )
Packit 6c4009
	    errstring = N_("invalid ELF header");
Packit 6c4009
	  else if (ehdr->e_ident[EI_CLASS] != ELFW(CLASS))
Packit 6c4009
	    {
Packit 6c4009
	      /* This is not a fatal error.  On architectures where
Packit 6c4009
		 32-bit and 64-bit binaries can be run this might
Packit 6c4009
		 happen.  */
Packit 6c4009
	      *found_other_class = true;
Packit 6c4009
	      goto close_and_out;
Packit 6c4009
	    }
Packit 6c4009
	  else if (ehdr->e_ident[EI_DATA] != byteorder)
Packit 6c4009
	    {
Packit 6c4009
	      if (BYTE_ORDER == BIG_ENDIAN)
Packit 6c4009
		errstring = N_("ELF file data encoding not big-endian");
Packit 6c4009
	      else
Packit 6c4009
		errstring = N_("ELF file data encoding not little-endian");
Packit 6c4009
	    }
Packit 6c4009
	  else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
Packit 6c4009
	    errstring
Packit 6c4009
	      = N_("ELF file version ident does not match current one");
Packit 6c4009
	  /* XXX We should be able so set system specific versions which are
Packit 6c4009
	     allowed here.  */
Packit 6c4009
	  else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI]))
Packit 6c4009
	    errstring = N_("ELF file OS ABI invalid");
Packit 6c4009
	  else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
Packit 6c4009
					  ehdr->e_ident[EI_ABIVERSION]))
Packit 6c4009
	    errstring = N_("ELF file ABI version invalid");
Packit 6c4009
	  else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD],
Packit 6c4009
			   EI_NIDENT - EI_PAD) != 0)
Packit 6c4009
	    errstring = N_("nonzero padding in e_ident");
Packit 6c4009
	  else
Packit 6c4009
	    /* Otherwise we don't know what went wrong.  */
Packit 6c4009
	    errstring = N_("internal error");
Packit 6c4009
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (ehdr->e_version != EV_CURRENT))
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("ELF file version does not match current one");
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
      if (! __glibc_likely (elf_machine_matches_host (ehdr)))
Packit 6c4009
	goto close_and_out;
Packit 6c4009
      else if (__glibc_unlikely (ehdr->e_type != ET_DYN
Packit 6c4009
				 && ehdr->e_type != ET_EXEC))
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("only ET_DYN and ET_EXEC can be loaded");
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
      else if (__glibc_unlikely (ehdr->e_type == ET_EXEC
Packit 6c4009
				 && (mode & __RTLD_OPENEXEC) == 0))
Packit 6c4009
	{
Packit 6c4009
	  /* BZ #16634. It is an error to dlopen ET_EXEC (unless
Packit 6c4009
	     __RTLD_OPENEXEC is explicitly set).  We return error here
Packit 6c4009
	     so that code in _dl_map_object_from_fd does not try to set
Packit 6c4009
	     l_tls_modid for this module.  */
Packit 6c4009
Packit 6c4009
	  errstring = N_("cannot dynamically load executable");
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
      else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr))))
Packit 6c4009
	{
Packit 6c4009
	  errstring = N_("ELF file's phentsize not the expected size");
Packit 6c4009
	  goto call_lose;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      maplength = ehdr->e_phnum * sizeof (ElfW(Phdr));
Packit 6c4009
      if (ehdr->e_phoff + maplength <= (size_t) fbp->len)
Packit 6c4009
	phdr = (void *) (fbp->buf + ehdr->e_phoff);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  phdr = alloca (maplength);
Packit 6c4009
	  __lseek (fd, ehdr->e_phoff, SEEK_SET);
Packit 6c4009
	  if ((size_t) __read_nocancel (fd, (void *) phdr, maplength)
Packit 6c4009
	      != maplength)
Packit 6c4009
	    {
Packit 6c4009
	    read_error:
Packit 6c4009
	      errval = errno;
Packit 6c4009
	      errstring = N_("cannot read file data");
Packit 6c4009
	      goto call_lose;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (elf_machine_reject_phdr_p
Packit 6c4009
			    (phdr, ehdr->e_phnum, fbp->buf, fbp->len,
Packit 6c4009
			     loader, fd)))
Packit 6c4009
	goto close_and_out;
Packit 6c4009
Packit 6c4009
      /* Check .note.ABI-tag if present.  */
Packit 6c4009
      for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
Packit 6c4009
	if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
Packit 6c4009
	  {
Packit 6c4009
	    ElfW(Addr) size = ph->p_filesz;
Packit 6c4009
	    /* NB: Some PT_NOTE segment may have alignment value of 0
Packit 6c4009
	       or 1.  gABI specifies that PT_NOTE segments should be
Packit 6c4009
	       aligned to 4 bytes in 32-bit objects and to 8 bytes in
Packit 6c4009
	       64-bit objects.  As a Linux extension, we also support
Packit 6c4009
	       4 byte alignment in 64-bit objects.  If p_align is less
Packit 6c4009
	       than 4, we treate alignment as 4 bytes since some note
Packit 6c4009
	       segments have 0 or 1 byte alignment.   */
Packit 6c4009
	    ElfW(Addr) align = ph->p_align;
Packit 6c4009
	    if (align < 4)
Packit 6c4009
	      align = 4;
Packit 6c4009
	    else if (align != 4 && align != 8)
Packit 6c4009
	      continue;
Packit 6c4009
Packit 6c4009
	    if (ph->p_offset + size <= (size_t) fbp->len)
Packit 6c4009
	      abi_note = (void *) (fbp->buf + ph->p_offset);
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		/* Note: __libc_use_alloca is not usable here, because
Packit 6c4009
		   thread info may not have been set up yet.  */
Packit 6c4009
		if (size < __MAX_ALLOCA_CUTOFF)
Packit 6c4009
		  abi_note = alloca (size);
Packit 6c4009
		else
Packit 6c4009
		  {
Packit 6c4009
		    /* There could be multiple PT_NOTEs.  */
Packit 6c4009
		    abi_note_malloced = realloc (abi_note_malloced, size);
Packit 6c4009
		    if (abi_note_malloced == NULL)
Packit 6c4009
		      goto read_error;
Packit 6c4009
Packit 6c4009
		    abi_note = abi_note_malloced;
Packit 6c4009
		  }
Packit 6c4009
		__lseek (fd, ph->p_offset, SEEK_SET);
Packit 6c4009
		if (__read_nocancel (fd, (void *) abi_note, size) != size)
Packit 6c4009
		  {
Packit 6c4009
		    free (abi_note_malloced);
Packit 6c4009
		    goto read_error;
Packit 6c4009
		  }
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
Packit 6c4009
	      {
Packit 6c4009
		ElfW(Addr) note_size
Packit 6c4009
		  = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1],
Packit 6c4009
					  align);
Packit 6c4009
Packit 6c4009
		if (size - 32 < note_size)
Packit 6c4009
		  {
Packit 6c4009
		    size = 0;
Packit 6c4009
		    break;
Packit 6c4009
		  }
Packit 6c4009
		size -= note_size;
Packit 6c4009
		abi_note = (void *) abi_note + note_size;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    if (size == 0)
Packit 6c4009
	      continue;
Packit 6c4009
Packit 6c4009
	    osversion = (abi_note[5] & 0xff) * 65536
Packit 6c4009
			+ (abi_note[6] & 0xff) * 256
Packit 6c4009
			+ (abi_note[7] & 0xff);
Packit 6c4009
	    if (abi_note[4] != __ABI_TAG_OS
Packit 6c4009
		|| (GLRO(dl_osversion) && GLRO(dl_osversion) < osversion))
Packit 6c4009
	      {
Packit 6c4009
	      close_and_out:
Packit 6c4009
		__close_nocancel (fd);
Packit 6c4009
		__set_errno (ENOENT);
Packit 6c4009
		fd = -1;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
      free (abi_note_malloced);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return fd;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Try to open NAME in one of the directories in *DIRSP.
Packit 6c4009
   Return the fd, or -1.  If successful, fill in *REALNAME
Packit 6c4009
   with the malloc'd full directory name.  If it turns out
Packit 6c4009
   that none of the directories in *DIRSP exists, *DIRSP is
Packit 6c4009
   replaced with (void *) -1, and the old value is free()d
Packit 6c4009
   if MAY_FREE_DIRS is true.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
open_path (const char *name, size_t namelen, int mode,
Packit 6c4009
	   struct r_search_path_struct *sps, char **realname,
Packit 6c4009
	   struct filebuf *fbp, struct link_map *loader, int whatcode,
Packit 6c4009
	   bool *found_other_class)
Packit 6c4009
{
Packit 6c4009
  struct r_search_path_elem **dirs = sps->dirs;
Packit 6c4009
  char *buf;
Packit 6c4009
  int fd = -1;
Packit 6c4009
  const char *current_what = NULL;
Packit 6c4009
  int any = 0;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (dirs == NULL))
Packit 6c4009
    /* We're called before _dl_init_paths when loading the main executable
Packit 6c4009
       given on the command line when rtld is run directly.  */
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  buf = alloca (max_dirnamelen + max_capstrlen + namelen);
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      struct r_search_path_elem *this_dir = *dirs;
Packit 6c4009
      size_t buflen = 0;
Packit 6c4009
      size_t cnt;
Packit 6c4009
      char *edp;
Packit 6c4009
      int here_any = 0;
Packit 6c4009
      int err;
Packit 6c4009
Packit 6c4009
      /* If we are debugging the search for libraries print the path
Packit 6c4009
	 now if it hasn't happened now.  */
Packit 6c4009
      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)
Packit 6c4009
	  && current_what != this_dir->what)
Packit 6c4009
	{
Packit 6c4009
	  current_what = this_dir->what;
Packit 6c4009
	  print_search_path (dirs, current_what, this_dir->where);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      edp = (char *) __mempcpy (buf, this_dir->dirname, this_dir->dirnamelen);
Packit 6c4009
      for (cnt = 0; fd == -1 && cnt < ncapstr; ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  /* Skip this directory if we know it does not exist.  */
Packit 6c4009
	  if (this_dir->status[cnt] == nonexisting)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  buflen =
Packit 6c4009
	    ((char *) __mempcpy (__mempcpy (edp, capstr[cnt].str,
Packit 6c4009
					    capstr[cnt].len),
Packit 6c4009
				 name, namelen)
Packit 6c4009
	     - buf);
Packit 6c4009
Packit 6c4009
	  /* Print name we try if this is wanted.  */
Packit 6c4009
	  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
Packit 6c4009
	    _dl_debug_printf ("  trying file=%s\n", buf);
Packit 6c4009
Packit 6c4009
	  fd = open_verify (buf, -1, fbp, loader, whatcode, mode,
Packit 6c4009
			    found_other_class, false);
Packit 6c4009
	  if (this_dir->status[cnt] == unknown)
Packit 6c4009
	    {
Packit 6c4009
	      if (fd != -1)
Packit 6c4009
		this_dir->status[cnt] = existing;
Packit 6c4009
	      /* Do not update the directory information when loading
Packit 6c4009
		 auditing code.  We must try to disturb the program as
Packit 6c4009
		 little as possible.  */
Packit 6c4009
	      else if (loader == NULL
Packit 6c4009
		       || GL(dl_ns)[loader->l_ns]._ns_loaded->l_auditing == 0)
Packit 6c4009
		{
Packit 6c4009
		  /* We failed to open machine dependent library.  Let's
Packit 6c4009
		     test whether there is any directory at all.  */
Packit 6c4009
		  struct stat64 st;
Packit 6c4009
Packit 6c4009
		  buf[buflen - namelen - 1] = '\0';
Packit 6c4009
Packit 6c4009
		  if (__xstat64 (_STAT_VER, buf, &st) != 0
Packit 6c4009
		      || ! S_ISDIR (st.st_mode))
Packit 6c4009
		    /* The directory does not exist or it is no directory.  */
Packit 6c4009
		    this_dir->status[cnt] = nonexisting;
Packit 6c4009
		  else
Packit 6c4009
		    this_dir->status[cnt] = existing;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Remember whether we found any existing directory.  */
Packit 6c4009
	  here_any |= this_dir->status[cnt] != nonexisting;
Packit 6c4009
Packit 6c4009
	  if (fd != -1 && __glibc_unlikely (mode & __RTLD_SECURE)
Packit 6c4009
	      && __libc_enable_secure)
Packit 6c4009
	    {
Packit 6c4009
	      /* This is an extra security effort to make sure nobody can
Packit 6c4009
		 preload broken shared objects which are in the trusted
Packit 6c4009
		 directories and so exploit the bugs.  */
Packit 6c4009
	      struct stat64 st;
Packit 6c4009
Packit 6c4009
	      if (__fxstat64 (_STAT_VER, fd, &st) != 0
Packit 6c4009
		  || (st.st_mode & S_ISUID) == 0)
Packit 6c4009
		{
Packit 6c4009
		  /* The shared object cannot be tested for being SUID
Packit 6c4009
		     or this bit is not set.  In this case we must not
Packit 6c4009
		     use this object.  */
Packit 6c4009
		  __close_nocancel (fd);
Packit 6c4009
		  fd = -1;
Packit 6c4009
		  /* We simply ignore the file, signal this by setting
Packit 6c4009
		     the error value which would have been set by `open'.  */
Packit 6c4009
		  errno = ENOENT;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (fd != -1)
Packit 6c4009
	{
Packit 6c4009
	  *realname = (char *) malloc (buflen);
Packit 6c4009
	  if (*realname != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      memcpy (*realname, buf, buflen);
Packit 6c4009
	      return fd;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      /* No memory for the name, we certainly won't be able
Packit 6c4009
		 to load and link it.  */
Packit 6c4009
	      __close_nocancel (fd);
Packit 6c4009
	      return -1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      if (here_any && (err = errno) != ENOENT && err != EACCES)
Packit 6c4009
	/* The file exists and is readable, but something went wrong.  */
Packit 6c4009
	return -1;
Packit 6c4009
Packit 6c4009
      /* Remember whether we found anything.  */
Packit 6c4009
      any |= here_any;
Packit 6c4009
    }
Packit 6c4009
  while (*++dirs != NULL);
Packit 6c4009
Packit 6c4009
  /* Remove the whole path if none of the directories exists.  */
Packit 6c4009
  if (__glibc_unlikely (! any))
Packit 6c4009
    {
Packit 6c4009
      /* Paths which were allocated using the minimal malloc() in ld.so
Packit 6c4009
	 must not be freed using the general free() in libc.  */
Packit 6c4009
      if (sps->malloced)
Packit 6c4009
	free (sps->dirs);
Packit 6c4009
Packit 6c4009
      /* rtld_search_dirs and env_path_list are attribute_relro, therefore
Packit 6c4009
	 avoid writing into it.  */
Packit 6c4009
      if (sps != &rtld_search_dirs && sps != &env_path_list)
Packit 6c4009
	sps->dirs = (void *) -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Map in the shared object file NAME.  */
Packit 6c4009
Packit 6c4009
struct link_map *
Packit 6c4009
_dl_map_object (struct link_map *loader, const char *name,
Packit 6c4009
		int type, int trace_mode, int mode, Lmid_t nsid)
Packit 6c4009
{
Packit 6c4009
  int fd;
Packit 6c4009
  const char *origname = NULL;
Packit 6c4009
  char *realname;
Packit 6c4009
  char *name_copy;
Packit 6c4009
  struct link_map *l;
Packit 6c4009
  struct filebuf fb;
Packit 6c4009
Packit 6c4009
  assert (nsid >= 0);
Packit 6c4009
  assert (nsid < GL(dl_nns));
Packit 6c4009
Packit 6c4009
  /* Look for this name among those already loaded.  */
Packit 6c4009
  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
Packit 6c4009
    {
Packit 6c4009
      /* If the requested name matches the soname of a loaded object,
Packit 6c4009
	 use that object.  Elide this check for names that have not
Packit 6c4009
	 yet been opened.  */
Packit 6c4009
      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
Packit 6c4009
	continue;
Packit 6c4009
      if (!_dl_name_match_p (name, l))
Packit 6c4009
	{
Packit 6c4009
	  const char *soname;
Packit 6c4009
Packit 6c4009
	  if (__glibc_likely (l->l_soname_added)
Packit 6c4009
	      || l->l_info[DT_SONAME] == NULL)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  soname = ((const char *) D_PTR (l, l_info[DT_STRTAB])
Packit 6c4009
		    + l->l_info[DT_SONAME]->d_un.d_val);
Packit 6c4009
	  if (strcmp (name, soname) != 0)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  /* We have a match on a new name -- cache it.  */
Packit 6c4009
	  add_name_to_object (l, soname);
Packit 6c4009
	  l->l_soname_added = 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* We have a match.  */
Packit 6c4009
      return l;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Display information if we are debugging.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
Packit 6c4009
      && loader != NULL)
Packit 6c4009
    _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
Packit 6c4009
		      ? "\nfile=%s [%lu];  needed by %s [%lu]\n"
Packit 6c4009
		      : "\nfile=%s [%lu];  dynamically loaded by %s [%lu]\n",
Packit 6c4009
		      name, nsid, DSO_FILENAME (loader->l_name), loader->l_ns);
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Give the auditing libraries a chance to change the name before we
Packit 6c4009
     try anything.  */
Packit 6c4009
  if (__glibc_unlikely (GLRO(dl_naudit) > 0)
Packit 6c4009
      && (loader == NULL || loader->l_auditing == 0))
Packit 6c4009
    {
Packit 6c4009
      struct audit_ifaces *afct = GLRO(dl_audit);
Packit 6c4009
      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (afct->objsearch != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      const char *before = name;
Packit 6c4009
	      name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
Packit 6c4009
				      LA_SER_ORIG);
Packit 6c4009
	      if (name == NULL)
Packit 6c4009
		{
Packit 6c4009
		  /* Do not try anything further.  */
Packit 6c4009
		  fd = -1;
Packit 6c4009
		  goto no_file;
Packit 6c4009
		}
Packit 6c4009
	      if (before != name && strcmp (before, name) != 0)
Packit 6c4009
		{
Packit 6c4009
		  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
Packit 6c4009
		    _dl_debug_printf ("audit changed filename %s -> %s\n",
Packit 6c4009
				      before, name);
Packit 6c4009
Packit 6c4009
		  if (origname == NULL)
Packit 6c4009
		    origname = before;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  afct = afct->next;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Will be true if we found a DSO which is of the other ELF class.  */
Packit 6c4009
  bool found_other_class = false;
Packit 6c4009
Packit 6c4009
  if (strchr (name, '/') == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Search for NAME in several places.  */
Packit 6c4009
Packit 6c4009
      size_t namelen = strlen (name) + 1;
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
Packit 6c4009
	_dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
Packit 6c4009
Packit 6c4009
      fd = -1;
Packit 6c4009
Packit 6c4009
      /* When the object has the RUNPATH information we don't use any
Packit 6c4009
	 RPATHs.  */
Packit 6c4009
      if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* This is the executable's map (if there is one).  Make sure that
Packit 6c4009
	     we do not look at it twice.  */
Packit 6c4009
	  struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit 6c4009
	  bool did_main_map = false;
Packit 6c4009
Packit 6c4009
	  /* First try the DT_RPATH of the dependent object that caused NAME
Packit 6c4009
	     to be loaded.  Then that object's dependent, and on up.  */
Packit 6c4009
	  for (l = loader; l; l = l->l_loader)
Packit 6c4009
	    if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
Packit 6c4009
	      {
Packit 6c4009
		fd = open_path (name, namelen, mode,
Packit 6c4009
				&l->l_rpath_dirs,
Packit 6c4009
				&realname, &fb, loader, LA_SER_RUNPATH,
Packit 6c4009
				&found_other_class);
Packit 6c4009
		if (fd != -1)
Packit 6c4009
		  break;
Packit 6c4009
Packit 6c4009
		did_main_map |= l == main_map;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	  /* If dynamically linked, try the DT_RPATH of the executable
Packit 6c4009
	     itself.  NB: we do this for lookups in any namespace.  */
Packit 6c4009
	  if (fd == -1 && !did_main_map
Packit 6c4009
	      && main_map != NULL && main_map->l_type != lt_loaded
Packit 6c4009
	      && cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
Packit 6c4009
			      "RPATH"))
Packit 6c4009
	    fd = open_path (name, namelen, mode,
Packit 6c4009
			    &main_map->l_rpath_dirs,
Packit 6c4009
			    &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
Packit 6c4009
			    &found_other_class);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Try the LD_LIBRARY_PATH environment variable.  */
Packit 6c4009
      if (fd == -1 && env_path_list.dirs != (void *) -1)
Packit 6c4009
	fd = open_path (name, namelen, mode, &env_path_list,
Packit 6c4009
			&realname, &fb,
Packit 6c4009
			loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
Packit 6c4009
			LA_SER_LIBPATH, &found_other_class);
Packit 6c4009
Packit 6c4009
      /* Look at the RUNPATH information for this binary.  */
Packit 6c4009
      if (fd == -1 && loader != NULL
Packit 6c4009
	  && cache_rpath (loader, &loader->l_runpath_dirs,
Packit 6c4009
			  DT_RUNPATH, "RUNPATH"))
Packit 6c4009
	fd = open_path (name, namelen, mode,
Packit 6c4009
			&loader->l_runpath_dirs, &realname, &fb, loader,
Packit 6c4009
			LA_SER_RUNPATH, &found_other_class);
Packit 6c4009
Packit 6c4009
      if (fd == -1)
Packit 6c4009
        {
Packit 6c4009
          realname = _dl_sysdep_open_object (name, namelen, &fd;;
Packit 6c4009
          if (realname != NULL)
Packit 6c4009
            {
Packit 6c4009
              fd = open_verify (realname, fd,
Packit 6c4009
                                &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
Packit 6c4009
                                LA_SER_CONFIG, mode, &found_other_class,
Packit 6c4009
                                false);
Packit 6c4009
              if (fd == -1)
Packit 6c4009
                free (realname);
Packit 6c4009
            }
Packit 6c4009
        }
Packit 6c4009
Packit 6c4009
#ifdef USE_LDCONFIG
Packit 6c4009
      if (fd == -1
Packit 6c4009
	  && (__glibc_likely ((mode & __RTLD_SECURE) == 0)
Packit 6c4009
	      || ! __libc_enable_secure)
Packit 6c4009
	  && __glibc_likely (GLRO(dl_inhibit_cache) == 0))
Packit 6c4009
	{
Packit 6c4009
	  /* Check the list of libraries in the file /etc/ld.so.cache,
Packit 6c4009
	     for compatibility with Linux's ldconfig program.  */
Packit 6c4009
	  char *cached = _dl_load_cache_lookup (name);
Packit 6c4009
Packit 6c4009
	  if (cached != NULL)
Packit 6c4009
	    {
Packit 6c4009
	      // XXX Correct to unconditionally default to namespace 0?
Packit 6c4009
	      l = (loader
Packit 6c4009
		   ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded
Packit 6c4009
# ifdef SHARED
Packit 6c4009
		   ?: &GL(dl_rtld_map)
Packit 6c4009
# endif
Packit 6c4009
		  );
Packit 6c4009
Packit 6c4009
	      /* If the loader has the DF_1_NODEFLIB flag set we must not
Packit 6c4009
		 use a cache entry from any of these directories.  */
Packit 6c4009
	      if (__glibc_unlikely (l->l_flags_1 & DF_1_NODEFLIB))
Packit 6c4009
		{
Packit 6c4009
		  const char *dirp = system_dirs;
Packit 6c4009
		  unsigned int cnt = 0;
Packit 6c4009
Packit 6c4009
		  do
Packit 6c4009
		    {
Packit 6c4009
		      if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
Packit 6c4009
			{
Packit 6c4009
			  /* The prefix matches.  Don't use the entry.  */
Packit 6c4009
			  free (cached);
Packit 6c4009
			  cached = NULL;
Packit 6c4009
			  break;
Packit 6c4009
			}
Packit 6c4009
Packit 6c4009
		      dirp += system_dirs_len[cnt] + 1;
Packit 6c4009
		      ++cnt;
Packit 6c4009
		    }
Packit 6c4009
		  while (cnt < nsystem_dirs_len);
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      if (cached != NULL)
Packit 6c4009
		{
Packit 6c4009
		  fd = open_verify (cached, -1,
Packit 6c4009
				    &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
Packit 6c4009
				    LA_SER_CONFIG, mode, &found_other_class,
Packit 6c4009
				    false);
Packit 6c4009
		  if (__glibc_likely (fd != -1))
Packit 6c4009
		    realname = cached;
Packit 6c4009
		  else
Packit 6c4009
		    free (cached);
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      /* Finally, try the default path.  */
Packit 6c4009
      if (fd == -1
Packit 6c4009
	  && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
Packit 6c4009
	      || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB)))
Packit 6c4009
	  && rtld_search_dirs.dirs != (void *) -1)
Packit 6c4009
	fd = open_path (name, namelen, mode, &rtld_search_dirs,
Packit 6c4009
			&realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
Packit 6c4009
Packit 6c4009
      /* Add another newline when we are tracing the library loading.  */
Packit 6c4009
      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
Packit 6c4009
	_dl_debug_printf ("\n");
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* The path may contain dynamic string tokens.  */
Packit 6c4009
      realname = (loader
Packit 6c4009
		  ? expand_dynamic_string_token (loader, name)
Packit 6c4009
		  : __strdup (name));
Packit 6c4009
      if (realname == NULL)
Packit 6c4009
	fd = -1;
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  fd = open_verify (realname, -1, &fb,
Packit 6c4009
			    loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
Packit 6c4009
			    &found_other_class, true);
Packit 6c4009
	  if (__glibc_unlikely (fd == -1))
Packit 6c4009
	    free (realname);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
 no_file:
Packit 6c4009
#endif
Packit 6c4009
  /* In case the LOADER information has only been provided to get to
Packit 6c4009
     the appropriate RUNPATH/RPATH information we do not need it
Packit 6c4009
     anymore.  */
Packit 6c4009
  if (mode & __RTLD_CALLMAP)
Packit 6c4009
    loader = NULL;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (fd == -1))
Packit 6c4009
    {
Packit 6c4009
      if (trace_mode
Packit 6c4009
	  && __glibc_likely ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) == 0))
Packit 6c4009
	{
Packit 6c4009
	  /* We haven't found an appropriate library.  But since we
Packit 6c4009
	     are only interested in the list of libraries this isn't
Packit 6c4009
	     so severe.  Fake an entry with all the information we
Packit 6c4009
	     have.  */
Packit 6c4009
	  static const Elf_Symndx dummy_bucket = STN_UNDEF;
Packit 6c4009
Packit 6c4009
	  /* Allocate a new object map.  */
Packit 6c4009
	  if ((name_copy = __strdup (name)) == NULL
Packit 6c4009
	      || (l = _dl_new_object (name_copy, name, type, loader,
Packit 6c4009
				      mode, nsid)) == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      free (name_copy);
Packit 6c4009
	      _dl_signal_error (ENOMEM, name, NULL,
Packit 6c4009
				N_("cannot create shared object descriptor"));
Packit 6c4009
	    }
Packit 6c4009
	  /* Signal that this is a faked entry.  */
Packit 6c4009
	  l->l_faked = 1;
Packit 6c4009
	  /* Since the descriptor is initialized with zero we do not
Packit 6c4009
	     have do this here.
Packit 6c4009
	  l->l_reserved = 0; */
Packit 6c4009
	  l->l_buckets = &dummy_bucket;
Packit 6c4009
	  l->l_nbuckets = 1;
Packit 6c4009
	  l->l_relocated = 1;
Packit 6c4009
Packit 6c4009
	  /* Enter the object in the object list.  */
Packit 6c4009
	  _dl_add_to_namespace_list (l, nsid);
Packit 6c4009
Packit 6c4009
	  return l;
Packit 6c4009
	}
Packit 6c4009
      else if (found_other_class)
Packit 6c4009
	_dl_signal_error (0, name, NULL,
Packit 6c4009
			  ELFW(CLASS) == ELFCLASS32
Packit 6c4009
			  ? N_("wrong ELF class: ELFCLASS64")
Packit 6c4009
			  : N_("wrong ELF class: ELFCLASS32"));
Packit 6c4009
      else
Packit 6c4009
	_dl_signal_error (errno, name, NULL,
Packit 6c4009
			  N_("cannot open shared object file"));
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  void *stack_end = __libc_stack_end;
Packit 6c4009
  return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
Packit 6c4009
				 type, mode, &stack_end, nsid);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
struct add_path_state
Packit 6c4009
{
Packit 6c4009
  bool counting;
Packit 6c4009
  unsigned int idx;
Packit 6c4009
  Dl_serinfo *si;
Packit 6c4009
  char *allocptr;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
add_path (struct add_path_state *p, const struct r_search_path_struct *sps,
Packit 6c4009
	  unsigned int flags)
Packit 6c4009
{
Packit 6c4009
  if (sps->dirs != (void *) -1)
Packit 6c4009
    {
Packit 6c4009
      struct r_search_path_elem **dirs = sps->dirs;
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  const struct r_search_path_elem *const r = *dirs++;
Packit 6c4009
	  if (p->counting)
Packit 6c4009
	    {
Packit 6c4009
	      p->si->dls_cnt++;
Packit 6c4009
	      p->si->dls_size += MAX (2, r->dirnamelen);
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      Dl_serpath *const sp = &p->si->dls_serpath[p->idx++];
Packit 6c4009
	      sp->dls_name = p->allocptr;
Packit 6c4009
	      if (r->dirnamelen < 2)
Packit 6c4009
		*p->allocptr++ = r->dirnamelen ? '/' : '.';
Packit 6c4009
	      else
Packit 6c4009
		p->allocptr = __mempcpy (p->allocptr,
Packit 6c4009
					  r->dirname, r->dirnamelen - 1);
Packit 6c4009
	      *p->allocptr++ = '\0';
Packit 6c4009
	      sp->dls_flags = flags;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      while (*dirs != NULL);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
Packit 6c4009
{
Packit 6c4009
  if (counting)
Packit 6c4009
    {
Packit 6c4009
      si->dls_cnt = 0;
Packit 6c4009
      si->dls_size = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  struct add_path_state p =
Packit 6c4009
    {
Packit 6c4009
      .counting = counting,
Packit 6c4009
      .idx = 0,
Packit 6c4009
      .si = si,
Packit 6c4009
      .allocptr = (char *) &si->dls_serpath[si->dls_cnt]
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
# define add_path(p, sps, flags) add_path(p, sps, 0) /* XXX */
Packit 6c4009
Packit 6c4009
  /* When the object has the RUNPATH information we don't use any RPATHs.  */
Packit 6c4009
  if (loader->l_info[DT_RUNPATH] == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* First try the DT_RPATH of the dependent object that caused NAME
Packit 6c4009
	 to be loaded.  Then that object's dependent, and on up.  */
Packit 6c4009
Packit 6c4009
      struct link_map *l = loader;
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
Packit 6c4009
	    add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
Packit 6c4009
	  l = l->l_loader;
Packit 6c4009
	}
Packit 6c4009
      while (l != NULL);
Packit 6c4009
Packit 6c4009
      /* If dynamically linked, try the DT_RPATH of the executable itself.  */
Packit 6c4009
      if (loader->l_ns == LM_ID_BASE)
Packit 6c4009
	{
Packit 6c4009
	  l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit 6c4009
	  if (l != NULL && l->l_type != lt_loaded && l != loader)
Packit 6c4009
	    if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
Packit 6c4009
	      add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Try the LD_LIBRARY_PATH environment variable.  */
Packit 6c4009
  add_path (&p, &env_path_list, XXX_ENV);
Packit 6c4009
Packit 6c4009
  /* Look at the RUNPATH information for this binary.  */
Packit 6c4009
  if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH"))
Packit 6c4009
    add_path (&p, &loader->l_runpath_dirs, XXX_RUNPATH);
Packit 6c4009
Packit 6c4009
  /* XXX
Packit 6c4009
     Here is where ld.so.cache gets checked, but we don't have
Packit 6c4009
     a way to indicate that in the results for Dl_serinfo.  */
Packit 6c4009
Packit 6c4009
  /* Finally, try the default path.  */
Packit 6c4009
  if (!(loader->l_flags_1 & DF_1_NODEFLIB))
Packit 6c4009
    add_path (&p, &rtld_search_dirs, XXX_default);
Packit 6c4009
Packit 6c4009
  if (counting)
Packit 6c4009
    /* Count the struct size before the string area, which we didn't
Packit 6c4009
       know before we completed dls_cnt.  */
Packit 6c4009
    si->dls_size += (char *) &si->dls_serpath[si->dls_cnt] - (char *) si;
Packit 6c4009
}