Blame elf/dl-support.c

Packit 6c4009
/* Support for dynamic linking code in static libc.
Packit 6c4009
   Copyright (C) 1996-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
/* This file defines some things that for the dynamic linker are defined in
Packit 6c4009
   rtld.c and dl-sysdep.c in ways appropriate to bootstrap dynamic linking.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <dl-machine.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include <dl-cache.h>
Packit 6c4009
#include <dl-librecon.h>
Packit 6c4009
#include <dl-procinfo.h>
Packit 6c4009
#include <unsecvars.h>
Packit 6c4009
#include <hp-timing.h>
Packit 6c4009
#include <stackinfo.h>
Packit 6c4009
Packit 6c4009
extern char *__progname;
Packit 6c4009
char **_dl_argv = &__progname;	/* This is checked for some error messages.  */
Packit 6c4009
Packit 6c4009
/* Name of the architecture.  */
Packit 6c4009
const char *_dl_platform;
Packit 6c4009
size_t _dl_platformlen;
Packit 6c4009
Packit 6c4009
int _dl_debug_mask;
Packit 6c4009
int _dl_lazy;
Packit 6c4009
ElfW(Addr) _dl_use_load_bias = -2;
Packit 6c4009
int _dl_dynamic_weak;
Packit 6c4009
Packit 6c4009
/* If nonzero print warnings about problematic situations.  */
Packit 6c4009
int _dl_verbose;
Packit 6c4009
Packit 6c4009
/* We never do profiling.  */
Packit 6c4009
const char *_dl_profile;
Packit 6c4009
const char *_dl_profile_output;
Packit 6c4009
Packit 6c4009
/* Names of shared object for which the RUNPATHs and RPATHs should be
Packit 6c4009
   ignored.  */
Packit 6c4009
const char *_dl_inhibit_rpath;
Packit 6c4009
Packit 6c4009
/* The map for the object we will profile.  */
Packit 6c4009
struct link_map *_dl_profile_map;
Packit 6c4009
Packit 6c4009
/* This is the address of the last stack address ever used.  */
Packit 6c4009
void *__libc_stack_end;
Packit 6c4009
Packit 6c4009
/* Path where the binary is found.  */
Packit 6c4009
const char *_dl_origin_path;
Packit 6c4009
Packit 6c4009
/* Nonzero if runtime lookup should not update the .got/.plt.  */
Packit 6c4009
int _dl_bind_not;
Packit 6c4009
Packit 6c4009
/* A dummy link map for the executable, used by dlopen to access the global
Packit 6c4009
   scope.  We don't export any symbols ourselves, so this can be minimal.  */
Packit 6c4009
static struct link_map _dl_main_map =
Packit 6c4009
  {
Packit 6c4009
    .l_name = (char *) "",
Packit 6c4009
    .l_real = &_dl_main_map,
Packit 6c4009
    .l_ns = LM_ID_BASE,
Packit 6c4009
    .l_libname = &(struct libname_list) { .name = "", .dont_free = 1 },
Packit 6c4009
    .l_searchlist =
Packit 6c4009
      {
Packit 6c4009
	.r_list = &(struct link_map *) { &_dl_main_map },
Packit 6c4009
	.r_nlist = 1,
Packit 6c4009
      },
Packit 6c4009
    .l_symbolic_searchlist = { .r_list = &(struct link_map *) { NULL } },
Packit 6c4009
    .l_type = lt_executable,
Packit 6c4009
    .l_scope_mem = { &_dl_main_map.l_searchlist },
Packit 6c4009
    .l_scope_max = (sizeof (_dl_main_map.l_scope_mem)
Packit 6c4009
		    / sizeof (_dl_main_map.l_scope_mem[0])),
Packit 6c4009
    .l_scope = _dl_main_map.l_scope_mem,
Packit 6c4009
    .l_local_scope = { &_dl_main_map.l_searchlist },
Packit 6c4009
    .l_used = 1,
Packit 6c4009
    .l_tls_offset = NO_TLS_OFFSET,
Packit 6c4009
    .l_serial = 1,
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* Namespace information.  */
Packit 6c4009
struct link_namespaces _dl_ns[DL_NNS] =
Packit 6c4009
  {
Packit 6c4009
    [LM_ID_BASE] =
Packit 6c4009
      {
Packit 6c4009
	._ns_loaded = &_dl_main_map,
Packit 6c4009
	._ns_nloaded = 1,
Packit 6c4009
	._ns_main_searchlist = &_dl_main_map.l_searchlist,
Packit 6c4009
      }
Packit 6c4009
  };
Packit 6c4009
size_t _dl_nns = 1;
Packit 6c4009
Packit 6c4009
/* Incremented whenever something may have been added to dl_loaded. */
Packit 6c4009
unsigned long long _dl_load_adds = 1;
Packit 6c4009
Packit 6c4009
/* Fake scope of the main application.  */
Packit 6c4009
struct r_scope_elem _dl_initial_searchlist =
Packit 6c4009
  {
Packit 6c4009
    .r_list = &(struct link_map *) { &_dl_main_map },
Packit 6c4009
    .r_nlist = 1,
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
/* Nonzero during startup.  */
Packit 6c4009
int _dl_starting_up = 1;
Packit 6c4009
Packit 6c4009
/* Random data provided by the kernel.  */
Packit 6c4009
void *_dl_random;
Packit 6c4009
Packit 6c4009
/* Get architecture specific initializer.  */
Packit 6c4009
#include <dl-procruntime.c>
Packit 6c4009
#include <dl-procinfo.c>
Packit 6c4009
Packit 6c4009
void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
Packit 6c4009
Packit 6c4009
size_t _dl_pagesize = EXEC_PAGESIZE;
Packit 6c4009
Packit 6c4009
int _dl_inhibit_cache;
Packit 6c4009
Packit 6c4009
unsigned int _dl_osversion;
Packit 6c4009
Packit 6c4009
/* All known directories in sorted order.  */
Packit 6c4009
struct r_search_path_elem *_dl_all_dirs;
Packit 6c4009
Packit 6c4009
/* All directories after startup.  */
Packit 6c4009
struct r_search_path_elem *_dl_init_all_dirs;
Packit 6c4009
Packit 6c4009
/* The object to be initialized first.  */
Packit 6c4009
struct link_map *_dl_initfirst;
Packit 6c4009
Packit 6c4009
/* Descriptor to write debug messages to.  */
Packit 6c4009
int _dl_debug_fd = STDERR_FILENO;
Packit 6c4009
Packit 6c4009
int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
Packit 6c4009
Packit 6c4009
ElfW(auxv_t) *_dl_auxv;
Packit 6c4009
const ElfW(Phdr) *_dl_phdr;
Packit 6c4009
size_t _dl_phnum;
Packit 6c4009
uint64_t _dl_hwcap __attribute__ ((nocommon));
Packit 6c4009
uint64_t _dl_hwcap2 __attribute__ ((nocommon));
Packit 6c4009
Packit 6c4009
/* The value of the FPU control word the kernel will preset in hardware.  */
Packit 6c4009
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
Packit 6c4009
Packit 6c4009
#if !HAVE_TUNABLES
Packit 6c4009
/* This is not initialized to HWCAP_IMPORTANT, matching the definition
Packit 6c4009
   of _dl_important_hwcaps, below, where no hwcap strings are ever
Packit 6c4009
   used.  This mask is still used to mediate the lookups in the cache
Packit 6c4009
   file.  Since there is no way to set this nonzero (we don't grok the
Packit 6c4009
   LD_HWCAP_MASK environment variable here), there is no real point in
Packit 6c4009
   setting _dl_hwcap nonzero below, but we do anyway.  */
Packit 6c4009
uint64_t _dl_hwcap_mask __attribute__ ((nocommon));
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Prevailing state of the stack.  Generally this includes PF_X, indicating it's
Packit 6c4009
 * executable but this isn't true for all platforms.  */
Packit 6c4009
ElfW(Word) _dl_stack_flags = DEFAULT_STACK_PERMS;
Packit 6c4009
Packit 6c4009
/* If loading a shared object requires that we make the stack executable
Packit 6c4009
   when it was not, we do it by calling this function.
Packit 6c4009
   It returns an errno code or zero on success.  */
Packit 6c4009
int (*_dl_make_stack_executable_hook) (void **) = _dl_make_stack_executable;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Function in libpthread to wait for termination of lookups.  */
Packit 6c4009
void (*_dl_wait_lookup_done) (void);
Packit 6c4009
Packit 6c4009
#if !THREAD_GSCOPE_IN_TCB
Packit 6c4009
int _dl_thread_gscope_count;
Packit 6c4009
#endif
Packit 6c4009
struct dl_scope_free_list *_dl_scope_free_list;
Packit 6c4009
Packit 6c4009
#ifdef NEED_DL_SYSINFO
Packit 6c4009
/* Needed for improved syscall handling on at least x86/Linux.  */
Packit 6c4009
uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT;
Packit 6c4009
#endif
Packit 6c4009
#ifdef NEED_DL_SYSINFO_DSO
Packit 6c4009
/* Address of the ELF headers in the vsyscall page.  */
Packit 6c4009
const ElfW(Ehdr) *_dl_sysinfo_dso;
Packit 6c4009
Packit 6c4009
struct link_map *_dl_sysinfo_map;
Packit 6c4009
Packit 6c4009
# include "get-dynamic-info.h"
Packit 6c4009
#endif
Packit 6c4009
#include "setup-vdso.h"
Packit 6c4009
Packit 6c4009
/* During the program run we must not modify the global data of
Packit 6c4009
   loaded shared object simultanously in two threads.  Therefore we
Packit 6c4009
   protect `_dl_open' and `_dl_close' in dl-close.c.
Packit 6c4009
Packit 6c4009
   This must be a recursive lock since the initializer function of
Packit 6c4009
   the loaded object might as well require a call to this function.
Packit 6c4009
   At this time it is not anymore a problem to modify the tables.  */
Packit 6c4009
__rtld_lock_define_initialized_recursive (, _dl_load_lock)
Packit 6c4009
/* This lock is used to keep __dl_iterate_phdr from inspecting the
Packit 6c4009
   list of loaded objects while an object is added to or removed from
Packit 6c4009
   that list.  */
Packit 6c4009
__rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef HAVE_AUX_VECTOR
Packit 6c4009
int _dl_clktck;
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_aux_init (ElfW(auxv_t) *av)
Packit 6c4009
{
Packit 6c4009
  int seen = 0;
Packit 6c4009
  uid_t uid = 0;
Packit 6c4009
  gid_t gid = 0;
Packit 6c4009
Packit 6c4009
  _dl_auxv = av;
Packit 6c4009
  for (; av->a_type != AT_NULL; ++av)
Packit 6c4009
    switch (av->a_type)
Packit 6c4009
      {
Packit 6c4009
      case AT_PAGESZ:
Packit 6c4009
	if (av->a_un.a_val != 0)
Packit 6c4009
	  GLRO(dl_pagesize) = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_CLKTCK:
Packit 6c4009
	GLRO(dl_clktck) = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_PHDR:
Packit 6c4009
	GL(dl_phdr) = (const void *) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_PHNUM:
Packit 6c4009
	GL(dl_phnum) = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_PLATFORM:
Packit 6c4009
	GLRO(dl_platform) = (void *) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_HWCAP:
Packit 6c4009
	GLRO(dl_hwcap) = (unsigned long int) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_HWCAP2:
Packit 6c4009
	GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_FPUCW:
Packit 6c4009
	GLRO(dl_fpu_control) = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#ifdef NEED_DL_SYSINFO
Packit 6c4009
      case AT_SYSINFO:
Packit 6c4009
	GL(dl_sysinfo) = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#endif
Packit 6c4009
#ifdef NEED_DL_SYSINFO_DSO
Packit 6c4009
      case AT_SYSINFO_EHDR:
Packit 6c4009
	GL(dl_sysinfo_dso) = (void *) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#endif
Packit 6c4009
      case AT_UID:
Packit 6c4009
	uid ^= av->a_un.a_val;
Packit 6c4009
	seen |= 1;
Packit 6c4009
	break;
Packit 6c4009
      case AT_EUID:
Packit 6c4009
	uid ^= av->a_un.a_val;
Packit 6c4009
	seen |= 2;
Packit 6c4009
	break;
Packit 6c4009
      case AT_GID:
Packit 6c4009
	gid ^= av->a_un.a_val;
Packit 6c4009
	seen |= 4;
Packit 6c4009
	break;
Packit 6c4009
      case AT_EGID:
Packit 6c4009
	gid ^= av->a_un.a_val;
Packit 6c4009
	seen |= 8;
Packit 6c4009
	break;
Packit 6c4009
      case AT_SECURE:
Packit 6c4009
	seen = -1;
Packit 6c4009
	__libc_enable_secure = av->a_un.a_val;
Packit 6c4009
	__libc_enable_secure_decided = 1;
Packit 6c4009
	break;
Packit 6c4009
      case AT_RANDOM:
Packit 6c4009
	_dl_random = (void *) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
# ifdef DL_PLATFORM_AUXV
Packit 6c4009
      DL_PLATFORM_AUXV
Packit 6c4009
# endif
Packit 6c4009
      }
Packit 6c4009
  if (seen == 0xf)
Packit 6c4009
    {
Packit 6c4009
      __libc_enable_secure = uid != 0 || gid != 0;
Packit 6c4009
      __libc_enable_secure_decided = 1;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_non_dynamic_init (void)
Packit 6c4009
{
Packit 6c4009
  _dl_main_map.l_origin = _dl_get_origin ();
Packit 6c4009
  _dl_main_map.l_phdr = GL(dl_phdr);
Packit 6c4009
  _dl_main_map.l_phnum = GL(dl_phnum);
Packit 6c4009
Packit 6c4009
  _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
Packit 6c4009
Packit 6c4009
  /* Set up the data structures for the system-supplied DSO early,
Packit 6c4009
     so they can influence _dl_init_paths.  */
Packit 6c4009
  setup_vdso (NULL, NULL);
Packit 6c4009
Packit 6c4009
  /* Initialize the data structures for the search paths for shared
Packit 6c4009
     objects.  */
Packit Service 358832
  _dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH",
Packit Service 358832
		  /* No glibc-hwcaps selection support in statically
Packit Service 358832
		     linked binaries.  */
Packit Service 358832
		  NULL, NULL);
Packit 6c4009
Packit 6c4009
  /* Remember the last search directory added at startup.  */
Packit 6c4009
  _dl_init_all_dirs = GL(dl_all_dirs);
Packit 6c4009
Packit 6c4009
  _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0';
Packit 6c4009
Packit 6c4009
  _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0';
Packit 6c4009
Packit 6c4009
  _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0';
Packit 6c4009
Packit 6c4009
  _dl_profile_output = getenv ("LD_PROFILE_OUTPUT");
Packit 6c4009
  if (_dl_profile_output == NULL || _dl_profile_output[0] == '\0')
Packit 6c4009
    _dl_profile_output
Packit 6c4009
      = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
Packit 6c4009
Packit 6c4009
  if (__libc_enable_secure)
Packit 6c4009
    {
Packit 6c4009
      static const char unsecure_envvars[] =
Packit 6c4009
	UNSECURE_ENVVARS
Packit 6c4009
#ifdef EXTRA_UNSECURE_ENVVARS
Packit 6c4009
	EXTRA_UNSECURE_ENVVARS
Packit 6c4009
#endif
Packit 6c4009
	;
Packit 6c4009
      const char *cp = unsecure_envvars;
Packit 6c4009
Packit 6c4009
      while (cp < unsecure_envvars + sizeof (unsecure_envvars))
Packit 6c4009
	{
Packit 6c4009
	  __unsetenv (cp);
Packit 6c4009
	  cp = (const char *) __rawmemchr (cp, '\0') + 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
#if !HAVE_TUNABLES
Packit 6c4009
      if (__access ("/etc/suid-debug", F_OK) != 0)
Packit 6c4009
	__unsetenv ("MALLOC_CHECK_");
Packit 6c4009
#endif
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#ifdef DL_PLATFORM_INIT
Packit 6c4009
  DL_PLATFORM_INIT;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef DL_OSVERSION_INIT
Packit 6c4009
  DL_OSVERSION_INIT;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Now determine the length of the platform string.  */
Packit 6c4009
  if (_dl_platform != NULL)
Packit 6c4009
    _dl_platformlen = strlen (_dl_platform);
Packit 6c4009
Packit 6c4009
  /* Scan for a program header telling us the stack is nonexecutable.  */
Packit 6c4009
  if (_dl_phdr != NULL)
Packit 6c4009
    for (uint_fast16_t i = 0; i < _dl_phnum; ++i)
Packit 6c4009
      if (_dl_phdr[i].p_type == PT_GNU_STACK)
Packit 6c4009
	{
Packit 6c4009
	  _dl_stack_flags = _dl_phdr[i].p_flags;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifdef DL_SYSINFO_IMPLEMENTATION
Packit 6c4009
DL_SYSINFO_IMPLEMENTATION
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if ENABLE_STATIC_PIE
Packit 6c4009
/* Since relocation to hidden _dl_main_map causes relocation overflow on
Packit 6c4009
   aarch64, a function is used to get the address of _dl_main_map.  */
Packit 6c4009
Packit 6c4009
struct link_map *
Packit 6c4009
_dl_get_dl_main_map (void)
Packit 6c4009
{
Packit 6c4009
  return &_dl_main_map;
Packit 6c4009
}
Packit 6c4009
#endif