Blame elf/dl-sysdep.c

Packit 6c4009
/* Operating system support for run-time dynamic linker.  Generic Unix version.
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
/* We conditionalize the whole of this file rather than simply eliding it
Packit 6c4009
   from the static build, because other sysdeps/ versions of this file
Packit 6c4009
   might define things needed by a static build.  */
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <elf.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <_itoa.h>
Packit 6c4009
#include <fpu_control.h>
Packit 6c4009
Packit 6c4009
#include <entry.h>
Packit 6c4009
#include <dl-machine.h>
Packit 6c4009
#include <dl-procinfo.h>
Packit 6c4009
#include <dl-osinfo.h>
Packit 6c4009
#include <libc-internal.h>
Packit 6c4009
#include <tls.h>
Packit 6c4009
Packit 6c4009
#include <dl-tunables.h>
Packit 6c4009
Packit 6c4009
extern char **_environ attribute_hidden;
Packit 6c4009
extern char _end[] attribute_hidden;
Packit 6c4009
Packit 6c4009
/* Protect SUID program against misuse of file descriptors.  */
Packit 6c4009
extern void __libc_check_standard_fds (void);
Packit 6c4009
Packit 6c4009
#ifdef NEED_DL_BASE_ADDR
Packit 6c4009
ElfW(Addr) _dl_base_addr;
Packit 6c4009
#endif
Packit 6c4009
int __libc_enable_secure attribute_relro = 0;
Packit 6c4009
rtld_hidden_data_def (__libc_enable_secure)
Packit 6c4009
int __libc_multiple_libcs = 0;	/* Defining this here avoids the inclusion
Packit 6c4009
				   of init-first.  */
Packit 6c4009
/* This variable contains the lowest stack address ever used.  */
Packit 6c4009
void *__libc_stack_end attribute_relro = NULL;
Packit 6c4009
rtld_hidden_data_def(__libc_stack_end)
Packit 6c4009
void *_dl_random attribute_relro = NULL;
Packit 6c4009
Packit 6c4009
#ifndef DL_FIND_ARG_COMPONENTS
Packit 6c4009
# define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp)	\
Packit 6c4009
  do {									      \
Packit 6c4009
    void **_tmp;							      \
Packit 6c4009
    (argc) = *(long int *) cookie;					      \
Packit 6c4009
    (argv) = (char **) ((long int *) cookie + 1);			      \
Packit 6c4009
    (envp) = (argv) + (argc) + 1;					      \
Packit 6c4009
    for (_tmp = (void **) (envp); *_tmp; ++_tmp)			      \
Packit 6c4009
      continue;								      \
Packit 6c4009
    (auxp) = (void *) ++_tmp;						      \
Packit 6c4009
  } while (0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef DL_STACK_END
Packit 6c4009
# define DL_STACK_END(cookie) ((void *) (cookie))
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
ElfW(Addr)
Packit 6c4009
_dl_sysdep_start (void **start_argptr,
Packit 6c4009
		  void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
Packit 6c4009
				   ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv))
Packit 6c4009
{
Packit 6c4009
  const ElfW(Phdr) *phdr = NULL;
Packit 6c4009
  ElfW(Word) phnum = 0;
Packit 6c4009
  ElfW(Addr) user_entry;
Packit 6c4009
  ElfW(auxv_t) *av;
Packit 6c4009
#ifdef HAVE_AUX_SECURE
Packit 6c4009
# define set_seen(tag) (tag)	/* Evaluate for the side effects.  */
Packit 6c4009
# define set_seen_secure() ((void) 0)
Packit 6c4009
#else
Packit 6c4009
  uid_t uid = 0;
Packit 6c4009
  gid_t gid = 0;
Packit 6c4009
  unsigned int seen = 0;
Packit 6c4009
# define set_seen_secure() (seen = -1)
Packit 6c4009
# ifdef HAVE_AUX_XID
Packit 6c4009
#  define set_seen(tag) (tag)	/* Evaluate for the side effects.  */
Packit 6c4009
# else
Packit 6c4009
#  define M(type) (1 << (type))
Packit 6c4009
#  define set_seen(tag) seen |= M ((tag)->a_type)
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
#ifdef NEED_DL_SYSINFO
Packit 6c4009
  uintptr_t new_sysinfo = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  __libc_stack_end = DL_STACK_END (start_argptr);
Packit 6c4009
  DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ,
Packit 6c4009
			  GLRO(dl_auxv));
Packit 6c4009
Packit 6c4009
  user_entry = (ElfW(Addr)) ENTRY_POINT;
Packit 6c4009
  GLRO(dl_platform) = NULL; /* Default to nothing known about the platform.  */
Packit 6c4009
Packit 6c4009
  for (av = GLRO(dl_auxv); av->a_type != AT_NULL; set_seen (av++))
Packit 6c4009
    switch (av->a_type)
Packit 6c4009
      {
Packit 6c4009
      case AT_PHDR:
Packit 6c4009
	phdr = (void *) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_PHNUM:
Packit 6c4009
	phnum = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_PAGESZ:
Packit 6c4009
	GLRO(dl_pagesize) = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_ENTRY:
Packit 6c4009
	user_entry = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#ifdef NEED_DL_BASE_ADDR
Packit 6c4009
      case AT_BASE:
Packit 6c4009
	_dl_base_addr = av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#endif
Packit 6c4009
#ifndef HAVE_AUX_SECURE
Packit 6c4009
      case AT_UID:
Packit 6c4009
      case AT_EUID:
Packit 6c4009
	uid ^= av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
      case AT_GID:
Packit 6c4009
      case AT_EGID:
Packit 6c4009
	gid ^= av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#endif
Packit 6c4009
      case AT_SECURE:
Packit 6c4009
#ifndef HAVE_AUX_SECURE
Packit 6c4009
	seen = -1;
Packit 6c4009
#endif
Packit 6c4009
	__libc_enable_secure = 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_CLKTCK:
Packit 6c4009
	GLRO(dl_clktck) = 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
	new_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
	GLRO(dl_sysinfo_dso) = (void *) av->a_un.a_val;
Packit 6c4009
	break;
Packit 6c4009
#endif
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
Packit 6c4009
#ifndef HAVE_AUX_SECURE
Packit 6c4009
  if (seen != -1)
Packit 6c4009
    {
Packit 6c4009
      /* Fill in the values we have not gotten from the kernel through the
Packit 6c4009
	 auxiliary vector.  */
Packit 6c4009
# ifndef HAVE_AUX_XID
Packit 6c4009
#  define SEE(UID, var, uid) \
Packit 6c4009
   if ((seen & M (AT_##UID)) == 0) var ^= __get##uid ()
Packit 6c4009
      SEE (UID, uid, uid);
Packit 6c4009
      SEE (EUID, uid, euid);
Packit 6c4009
      SEE (GID, gid, gid);
Packit 6c4009
      SEE (EGID, gid, egid);
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
      /* If one of the two pairs of IDs does not match this is a setuid
Packit 6c4009
	 or setgid run.  */
Packit 6c4009
      __libc_enable_secure = uid | gid;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef HAVE_AUX_PAGESIZE
Packit 6c4009
  if (GLRO(dl_pagesize) == 0)
Packit 6c4009
    GLRO(dl_pagesize) = __getpagesize ();
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef NEED_DL_SYSINFO
Packit 6c4009
  if (new_sysinfo != 0)
Packit 6c4009
    {
Packit 6c4009
# ifdef NEED_DL_SYSINFO_DSO
Packit 6c4009
      /* Only set the sysinfo value if we also have the vsyscall DSO.  */
Packit 6c4009
      if (GLRO(dl_sysinfo_dso) != 0)
Packit 6c4009
# endif
Packit 6c4009
        GLRO(dl_sysinfo) = new_sysinfo;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  __tunables_init (_environ);
Packit 6c4009
Packit 6c4009
#ifdef DL_SYSDEP_INIT
Packit 6c4009
  DL_SYSDEP_INIT;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef DL_PLATFORM_INIT
Packit 6c4009
  DL_PLATFORM_INIT;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Determine the length of the platform name.  */
Packit 6c4009
  if (GLRO(dl_platform) != NULL)
Packit 6c4009
    GLRO(dl_platformlen) = strlen (GLRO(dl_platform));
Packit 6c4009
Packit 6c4009
  if (__sbrk (0) == _end)
Packit 6c4009
    /* The dynamic linker was run as a program, and so the initial break
Packit 6c4009
       starts just after our bss, at &_end.  The malloc in dl-minimal.c
Packit 6c4009
       will consume the rest of this page, so tell the kernel to move the
Packit 6c4009
       break up that far.  When the user program examines its break, it
Packit 6c4009
       will see this new value and not clobber our data.  */
Packit 6c4009
    __sbrk (GLRO(dl_pagesize)
Packit 6c4009
	    - ((_end - (char *) 0) & (GLRO(dl_pagesize) - 1)));
Packit 6c4009
Packit 6c4009
  /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
Packit 6c4009
     allocated.  If necessary we are doing it ourself.  If it is not
Packit 6c4009
     possible we stop the program.  */
Packit 6c4009
  if (__builtin_expect (__libc_enable_secure, 0))
Packit 6c4009
    __libc_check_standard_fds ();
Packit 6c4009
Packit 6c4009
  (*dl_main) (phdr, phnum, &user_entry, GLRO(dl_auxv));
Packit 6c4009
  return user_entry;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_sysdep_start_cleanup (void)
Packit 6c4009
{
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_dl_show_auxv (void)
Packit 6c4009
{
Packit 6c4009
  char buf[64];
Packit 6c4009
  ElfW(auxv_t) *av;
Packit 6c4009
Packit 6c4009
  /* Terminate string.  */
Packit 6c4009
  buf[63] = '\0';
Packit 6c4009
Packit 6c4009
  /* The following code assumes that the AT_* values are encoded
Packit 6c4009
     starting from 0 with AT_NULL, 1 for AT_IGNORE, and all other values
Packit 6c4009
     close by (otherwise the array will be too large).  In case we have
Packit 6c4009
     to support a platform where these requirements are not fulfilled
Packit 6c4009
     some alternative implementation has to be used.  */
Packit 6c4009
  for (av = GLRO(dl_auxv); av->a_type != AT_NULL; ++av)
Packit 6c4009
    {
Packit 6c4009
      static const struct
Packit 6c4009
      {
Packit 6c4009
	const char label[17];
Packit 6c4009
	enum { unknown = 0, dec, hex, str, ignore } form : 8;
Packit 6c4009
      } auxvars[] =
Packit 6c4009
	{
Packit 6c4009
	  [AT_EXECFD - 2] =		{ "EXECFD:       ", dec },
Packit 6c4009
	  [AT_EXECFN - 2] =		{ "EXECFN:       ", str },
Packit 6c4009
	  [AT_PHDR - 2] =		{ "PHDR:         0x", hex },
Packit 6c4009
	  [AT_PHENT - 2] =		{ "PHENT:        ", dec },
Packit 6c4009
	  [AT_PHNUM - 2] =		{ "PHNUM:        ", dec },
Packit 6c4009
	  [AT_PAGESZ - 2] =		{ "PAGESZ:       ", dec },
Packit 6c4009
	  [AT_BASE - 2] =		{ "BASE:         0x", hex },
Packit 6c4009
	  [AT_FLAGS - 2] =		{ "FLAGS:        0x", hex },
Packit 6c4009
	  [AT_ENTRY - 2] =		{ "ENTRY:        0x", hex },
Packit 6c4009
	  [AT_NOTELF - 2] =		{ "NOTELF:       ", hex },
Packit 6c4009
	  [AT_UID - 2] =		{ "UID:          ", dec },
Packit 6c4009
	  [AT_EUID - 2] =		{ "EUID:         ", dec },
Packit 6c4009
	  [AT_GID - 2] =		{ "GID:          ", dec },
Packit 6c4009
	  [AT_EGID - 2] =		{ "EGID:         ", dec },
Packit 6c4009
	  [AT_PLATFORM - 2] =		{ "PLATFORM:     ", str },
Packit 6c4009
	  [AT_HWCAP - 2] =		{ "HWCAP:        ", hex },
Packit 6c4009
	  [AT_CLKTCK - 2] =		{ "CLKTCK:       ", dec },
Packit 6c4009
	  [AT_FPUCW - 2] =		{ "FPUCW:        ", hex },
Packit 6c4009
	  [AT_DCACHEBSIZE - 2] =	{ "DCACHEBSIZE:  0x", hex },
Packit 6c4009
	  [AT_ICACHEBSIZE - 2] =	{ "ICACHEBSIZE:  0x", hex },
Packit 6c4009
	  [AT_UCACHEBSIZE - 2] =	{ "UCACHEBSIZE:  0x", hex },
Packit 6c4009
	  [AT_IGNOREPPC - 2] =		{ "IGNOREPPC", ignore },
Packit 6c4009
	  [AT_SECURE - 2] =		{ "SECURE:       ", dec },
Packit 6c4009
	  [AT_BASE_PLATFORM - 2] =	{ "BASE_PLATFORM:", str },
Packit 6c4009
	  [AT_SYSINFO - 2] =		{ "SYSINFO:      0x", hex },
Packit 6c4009
	  [AT_SYSINFO_EHDR - 2] =	{ "SYSINFO_EHDR: 0x", hex },
Packit 6c4009
	  [AT_RANDOM - 2] =		{ "RANDOM:       0x", hex },
Packit 6c4009
	  [AT_HWCAP2 - 2] =		{ "HWCAP2:       0x", hex },
Packit 6c4009
	};
Packit 6c4009
      unsigned int idx = (unsigned int) (av->a_type - 2);
Packit 6c4009
Packit 6c4009
      if ((unsigned int) av->a_type < 2u
Packit 6c4009
	  || (idx < sizeof (auxvars) / sizeof (auxvars[0])
Packit 6c4009
	      && auxvars[idx].form == ignore))
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      assert (AT_NULL == 0);
Packit 6c4009
      assert (AT_IGNORE == 1);
Packit 6c4009
Packit 6c4009
      if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2)
Packit 6c4009
	{
Packit 6c4009
	  /* These are handled in a special way per platform.  */
Packit 6c4009
	  if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (idx < sizeof (auxvars) / sizeof (auxvars[0])
Packit 6c4009
	  && auxvars[idx].form != unknown)
Packit 6c4009
	{
Packit 6c4009
	  const char *val = (char *) av->a_un.a_val;
Packit 6c4009
Packit 6c4009
	  if (__builtin_expect (auxvars[idx].form, dec) == dec)
Packit 6c4009
	    val = _itoa ((unsigned long int) av->a_un.a_val,
Packit 6c4009
			 buf + sizeof buf - 1, 10, 0);
Packit 6c4009
	  else if (__builtin_expect (auxvars[idx].form, hex) == hex)
Packit 6c4009
	    val = _itoa ((unsigned long int) av->a_un.a_val,
Packit 6c4009
			 buf + sizeof buf - 1, 16, 0);
Packit 6c4009
Packit 6c4009
	  _dl_printf ("AT_%s%s\n", auxvars[idx].label, val);
Packit 6c4009
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Unknown value: print a generic line.  */
Packit 6c4009
      char buf2[17];
Packit 6c4009
      buf2[sizeof (buf2) - 1] = '\0';
Packit 6c4009
      const char *val2 = _itoa ((unsigned long int) av->a_un.a_val,
Packit 6c4009
				buf2 + sizeof buf2 - 1, 16, 0);
Packit 6c4009
      const char *val =  _itoa ((unsigned long int) av->a_type,
Packit 6c4009
				buf + sizeof buf - 1, 16, 0);
Packit 6c4009
      _dl_printf ("AT_??? (0x%s): 0x%s\n", val, val2);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif