Blame elf/dl-object.c

Packit 6c4009
/* Storage management for the chain of loaded shared objects.
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 <errno.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Add the new link_map NEW to the end of the namespace list.  */
Packit 6c4009
void
Packit 6c4009
_dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
Packit 6c4009
{
Packit 6c4009
  /* We modify the list of loaded objects.  */
Packit 6c4009
  __rtld_lock_lock_recursive (GL(dl_load_write_lock));
Packit 6c4009
Packit 6c4009
  if (GL(dl_ns)[nsid]._ns_loaded != NULL)
Packit 6c4009
    {
Packit 6c4009
      struct link_map *l = GL(dl_ns)[nsid]._ns_loaded;
Packit 6c4009
      while (l->l_next != NULL)
Packit 6c4009
	l = l->l_next;
Packit 6c4009
      new->l_prev = l;
Packit 6c4009
      /* new->l_next = NULL;   Would be necessary but we use calloc.  */
Packit 6c4009
      l->l_next = new;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    GL(dl_ns)[nsid]._ns_loaded = new;
Packit 6c4009
  ++GL(dl_ns)[nsid]._ns_nloaded;
Packit 6c4009
  new->l_serial = GL(dl_load_adds);
Packit 6c4009
  ++GL(dl_load_adds);
Packit 6c4009
Packit 6c4009
  __rtld_lock_unlock_recursive (GL(dl_load_write_lock));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Allocate a `struct link_map' for a new object being loaded,
Packit 6c4009
   and enter it into the _dl_loaded list.  */
Packit 6c4009
struct link_map *
Packit 6c4009
_dl_new_object (char *realname, const char *libname, int type,
Packit 6c4009
		struct link_map *loader, int mode, Lmid_t nsid)
Packit 6c4009
{
Packit Service a01622
#ifdef SHARED
Packit Service a01622
  unsigned int naudit;
Packit Service a01622
  if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0))
Packit Service a01622
    {
Packit Service a01622
      assert (type == lt_executable);
Packit Service a01622
      assert (nsid == LM_ID_BASE);
Packit Service a01622
Packit Service a01622
      /* Ignore the specified libname for the main executable.  It is
Packit Service a01622
	 only known with an explicit loader invocation.  */
Packit Service a01622
      libname = "";
Packit Service a01622
Packit Service a01622
      /* We create the map for the executable before we know whether
Packit Service a01622
	 we have auditing libraries and if yes, how many.  Assume the
Packit Service a01622
	 worst.  */
Packit Service a01622
      naudit = DL_NNS;
Packit Service a01622
    }
Packit Service a01622
  else
Packit Service a01622
    naudit = GLRO (dl_naudit);
Packit Service a01622
#endif
Packit Service a01622
Packit 6c4009
  size_t libname_len = strlen (libname) + 1;
Packit 6c4009
  struct link_map *new;
Packit 6c4009
  struct libname_list *newname;
Packit 6c4009
#ifdef SHARED
Packit Service 2598ba
  size_t audit_space = naudit * sizeof (struct auditstate);
Packit 6c4009
#else
Packit 6c4009
# define audit_space 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  new = (struct link_map *) calloc (sizeof (*new) + audit_space
Packit 6c4009
				    + sizeof (struct link_map *)
Packit 6c4009
				    + sizeof (*newname) + libname_len, 1);
Packit 6c4009
  if (new == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  new->l_real = new;
Packit 6c4009
  new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1)
Packit 6c4009
							    + audit_space);
Packit 6c4009
Packit 6c4009
  new->l_libname = newname
Packit 6c4009
    = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1);
Packit 6c4009
  newname->name = (char *) memcpy (newname + 1, libname, libname_len);
Packit 6c4009
  /* newname->next = NULL;	We use calloc therefore not necessary.  */
Packit 6c4009
  newname->dont_free = 1;
Packit 6c4009
Packit 6c4009
  /* When we create the executable link map, or a VDSO link map, we start
Packit 6c4009
     with "" for the l_name. In these cases "" points to ld.so rodata
Packit 6c4009
     and won't get dumped during core file generation. Therefore to assist
Packit 6c4009
     gdb and to create more self-contained core files we adjust l_name to
Packit 6c4009
     point at the newly allocated copy (which will get dumped) instead of
Packit Service a01622
     the ld.so rodata copy.
Packit Service a01622
Packit Service a01622
     Furthermore, in case of explicit loader invocation, discard the
Packit Service a01622
     name of the main executable, to match the regular behavior, where
Packit Service a01622
     name of the executable is not known.  */
Packit Service a01622
#ifdef SHARED
Packit Service a01622
  if (*realname != '\0' && (mode & __RTLD_OPENEXEC) == 0)
Packit Service a01622
#else
Packit Service a01622
  if (*realname != '\0')
Packit Service a01622
#endif
Packit Service a01622
    new->l_name = realname;
Packit Service a01622
  else
Packit Service a01622
    new->l_name = (char *) newname->name + libname_len - 1;
Packit Service a01622
Packit 6c4009
  new->l_type = type;
Packit 6c4009
  /* If we set the bit now since we know it is never used we avoid
Packit 6c4009
     dirtying the cache line later.  */
Packit 6c4009
  if ((GLRO(dl_debug_mask) & DL_DEBUG_UNUSED) == 0)
Packit 6c4009
    new->l_used = 1;
Packit 6c4009
  new->l_loader = loader;
Packit 6c4009
#if NO_TLS_OFFSET != 0
Packit 6c4009
  new->l_tls_offset = NO_TLS_OFFSET;
Packit 6c4009
#endif
Packit 6c4009
  new->l_ns = nsid;
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  for (unsigned int cnt = 0; cnt < naudit; ++cnt)
Packit Service 2598ba
    /* No need to initialize bindflags due to calloc.  */
Packit Service 2598ba
    link_map_audit_state (new, cnt)->cookie = (uintptr_t) new;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* new->l_global = 0;	We use calloc therefore not necessary.  */
Packit 6c4009
Packit 6c4009
  /* Use the 'l_scope_mem' array by default for the 'l_scope'
Packit 6c4009
     information.  If we need more entries we will allocate a large
Packit 6c4009
     array dynamically.  */
Packit 6c4009
  new->l_scope = new->l_scope_mem;
Packit 6c4009
  new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
Packit 6c4009
Packit 6c4009
  /* Counter for the scopes we have to handle.  */
Packit 6c4009
  int idx = 0;
Packit 6c4009
Packit 6c4009
  if (GL(dl_ns)[nsid]._ns_loaded != NULL)
Packit 6c4009
    /* Add the global scope.  */
Packit 6c4009
    new->l_scope[idx++] = &GL(dl_ns)[nsid]._ns_loaded->l_searchlist;
Packit 6c4009
Packit 6c4009
  /* If we have no loader the new object acts as it.  */
Packit 6c4009
  if (loader == NULL)
Packit 6c4009
    loader = new;
Packit 6c4009
  else
Packit 6c4009
    /* Determine the local scope.  */
Packit 6c4009
    while (loader->l_loader != NULL)
Packit 6c4009
      loader = loader->l_loader;
Packit 6c4009
Packit 6c4009
  /* Insert the scope if it isn't the global scope we already added.  */
Packit 6c4009
  if (idx == 0 || &loader->l_searchlist != new->l_scope[0])
Packit 6c4009
    {
Packit 6c4009
      if ((mode & RTLD_DEEPBIND) != 0 && idx != 0)
Packit 6c4009
	{
Packit 6c4009
	  new->l_scope[1] = new->l_scope[0];
Packit 6c4009
	  idx = 0;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      new->l_scope[idx] = &loader->l_searchlist;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  new->l_local_scope[0] = &new->l_searchlist;
Packit 6c4009
Packit Service a01622
  /* Determine the origin.  If allocating the link map for the main
Packit Service a01622
     executable, the realname is not known and "".  In this case, the
Packit Service a01622
     origin needs to be determined by other means.  However, in case
Packit Service a01622
     of an explicit loader invocation, the pathname of the main
Packit Service a01622
     executable is known and needs to be processed here: From the
Packit Service a01622
     point of view of the kernel, the main executable is the
Packit Service a01622
     dynamic loader, and this would lead to a computation of the wrong
Packit Service a01622
     origin.  */
Packit 6c4009
  if (realname[0] != '\0')
Packit 6c4009
    {
Packit 6c4009
      size_t realname_len = strlen (realname) + 1;
Packit 6c4009
      char *origin;
Packit 6c4009
      char *cp;
Packit 6c4009
Packit 6c4009
      if (realname[0] == '/')
Packit 6c4009
	{
Packit 6c4009
	  /* It is an absolute path.  Use it.  But we have to make a
Packit 6c4009
	     copy since we strip out the trailing slash.  */
Packit 6c4009
	  cp = origin = (char *) malloc (realname_len);
Packit 6c4009
	  if (origin == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      origin = (char *) -1;
Packit 6c4009
	      goto out;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  size_t len = realname_len;
Packit 6c4009
	  char *result = NULL;
Packit 6c4009
Packit 6c4009
	  /* Get the current directory name.  */
Packit 6c4009
	  origin = NULL;
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      char *new_origin;
Packit 6c4009
Packit 6c4009
	      len += 128;
Packit 6c4009
	      new_origin = (char *) realloc (origin, len);
Packit 6c4009
	      if (new_origin == NULL)
Packit 6c4009
		/* We exit the loop.  Note that result == NULL.  */
Packit 6c4009
		break;
Packit 6c4009
	      origin = new_origin;
Packit 6c4009
	    }
Packit 6c4009
	  while ((result = __getcwd (origin, len - realname_len)) == NULL
Packit 6c4009
		 && errno == ERANGE);
Packit 6c4009
Packit 6c4009
	  if (result == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /* We were not able to determine the current directory.
Packit 6c4009
		 Note that free(origin) is OK if origin == NULL.  */
Packit 6c4009
	      free (origin);
Packit 6c4009
	      origin = (char *) -1;
Packit 6c4009
	      goto out;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Find the end of the path and see whether we have to add a
Packit 6c4009
	     slash.  We could use rawmemchr but this need not be
Packit 6c4009
	     fast.  */
Packit 6c4009
	  cp = (strchr) (origin, '\0');
Packit 6c4009
	  if (cp[-1] != '/')
Packit 6c4009
	    *cp++ = '/';
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Add the real file name.  */
Packit 6c4009
      cp = __mempcpy (cp, realname, realname_len);
Packit 6c4009
Packit 6c4009
      /* Now remove the filename and the slash.  Leave the slash if
Packit 6c4009
	 the name is something like "/foo".  */
Packit 6c4009
      do
Packit 6c4009
	--cp;
Packit 6c4009
      while (*cp != '/');
Packit 6c4009
Packit 6c4009
      if (cp == origin)
Packit 6c4009
	/* Keep the only slash which is the first character.  */
Packit 6c4009
	++cp;
Packit 6c4009
      *cp = '\0';
Packit 6c4009
Packit 6c4009
    out:
Packit 6c4009
      new->l_origin = origin;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return new;
Packit 6c4009
}