Blame elf/dl-sym.c

Packit 6c4009
/* Look up a symbol in a shared object loaded by `dlopen'.
Packit 6c4009
   Copyright (C) 1999-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 <assert.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <dl-hash.h>
Packit 6c4009
#include <sysdep-cancel.h>
Packit 6c4009
#include <dl-tls.h>
Packit 6c4009
#include <dl-irel.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
/* Systems which do not have tls_index also probably have to define
Packit 6c4009
   DONT_USE_TLS_INDEX.  */
Packit 6c4009
Packit 6c4009
# ifndef __TLS_GET_ADDR
Packit 6c4009
#  define __TLS_GET_ADDR __tls_get_addr
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
/* Return the symbol address given the map of the module it is in and
Packit 6c4009
   the symbol record.  This is used in dl-sym.c.  */
Packit 6c4009
static void *
Packit 6c4009
_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
Packit 6c4009
{
Packit 6c4009
# ifndef DONT_USE_TLS_INDEX
Packit 6c4009
  tls_index tmp =
Packit 6c4009
    {
Packit 6c4009
      .ti_module = map->l_tls_modid,
Packit 6c4009
      .ti_offset = ref->st_value
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  return __TLS_GET_ADDR (&tmp);
Packit 6c4009
# else
Packit 6c4009
  return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
Packit 6c4009
# endif
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct call_dl_lookup_args
Packit 6c4009
{
Packit 6c4009
  /* Arguments to do_dlsym.  */
Packit 6c4009
  struct link_map *map;
Packit 6c4009
  const char *name;
Packit 6c4009
  struct r_found_version *vers;
Packit 6c4009
  int flags;
Packit 6c4009
Packit 6c4009
  /* Return values of do_dlsym.  */
Packit 6c4009
  lookup_t loadbase;
Packit 6c4009
  const ElfW(Sym) **refp;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
call_dl_lookup (void *ptr)
Packit 6c4009
{
Packit 6c4009
  struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
Packit 6c4009
  args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
Packit 6c4009
					args->map->l_scope, args->vers, 0,
Packit 6c4009
					args->flags, NULL);
Packit 6c4009
}
Packit 6c4009
Packit Bot 0c2104
Packit 6c4009
static void *
Packit 6c4009
do_sym (void *handle, const char *name, void *who,
Packit 6c4009
	struct r_found_version *vers, int flags)
Packit 6c4009
{
Packit 6c4009
  const ElfW(Sym) *ref = NULL;
Packit 6c4009
  lookup_t result;
Packit 6c4009
  ElfW(Addr) caller = (ElfW(Addr)) who;
Packit 6c4009
Packit Bot 0c2104
  struct link_map *l = _dl_find_dso_for_object (caller);
Packit Bot 0c2104
  /* If the address is not recognized the call comes from the main
Packit Bot 0c2104
     program (we hope).  */
Packit Bot 0c2104
  struct link_map *match = l ? l : GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit 6c4009
Packit 6c4009
  if (handle == RTLD_DEFAULT)
Packit 6c4009
    {
Packit 6c4009
      /* Search the global scope.  We have the simple case where
Packit 6c4009
	 we look up in the scope of an object which was part of
Packit 6c4009
	 the initial binary.  And then the more complex part
Packit 6c4009
	 where the object is dynamically loaded and the scope
Packit 6c4009
	 array can change.  */
Packit 6c4009
      if (RTLD_SINGLE_THREAD_P)
Packit 6c4009
	result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
Packit 6c4009
					   match->l_scope, vers, 0,
Packit 6c4009
					   flags | DL_LOOKUP_ADD_DEPENDENCY,
Packit 6c4009
					   NULL);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  struct call_dl_lookup_args args;
Packit 6c4009
	  args.name = name;
Packit 6c4009
	  args.map = match;
Packit 6c4009
	  args.vers = vers;
Packit 6c4009
	  args.flags
Packit 6c4009
	    = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
Packit 6c4009
	  args.refp = &ref;
Packit 6c4009
Packit 6c4009
	  THREAD_GSCOPE_SET_FLAG ();
Packit 6c4009
	  struct dl_exception exception;
Packit 6c4009
	  int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
Packit 6c4009
	  THREAD_GSCOPE_RESET_FLAG ();
Packit 6c4009
	  if (__glibc_unlikely (exception.errstring != NULL))
Packit 6c4009
	    _dl_signal_exception (err, &exception, NULL);
Packit 6c4009
Packit 6c4009
	  result = args.map;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else if (handle == RTLD_NEXT)
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
Packit 6c4009
	{
Packit 6c4009
	  if (match == NULL
Packit 6c4009
	      || caller < match->l_map_start
Packit 6c4009
	      || caller >= match->l_map_end)
Packit 6c4009
	    _dl_signal_error (0, NULL, NULL, N_("\
Packit 6c4009
RTLD_NEXT used in code not dynamically loaded"));
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      struct link_map *l = match;
Packit 6c4009
      while (l->l_loader != NULL)
Packit 6c4009
	l = l->l_loader;
Packit 6c4009
Packit 6c4009
      result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
Packit 6c4009
					 vers, 0, 0, match);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Search the scope of the given object.  */
Packit 6c4009
      struct link_map *map = handle;
Packit 6c4009
      result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
Packit 6c4009
					 vers, 0, flags, NULL);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (ref != NULL)
Packit 6c4009
    {
Packit 6c4009
      void *value;
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
      if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
Packit 6c4009
	/* The found symbol is a thread-local storage variable.
Packit 6c4009
	   Return the address for to the current thread.  */
Packit 6c4009
	value = _dl_tls_symaddr (result, ref);
Packit 6c4009
      else
Packit 6c4009
#endif
Packit 6c4009
	value = DL_SYMBOL_ADDRESS (result, ref);
Packit 6c4009
Packit Bot 0c2104
      /* Resolve indirect function address.  */
Packit Bot 0c2104
      if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
Packit Bot 0c2104
	{
Packit Bot 0c2104
	  DL_FIXUP_VALUE_TYPE fixup
Packit Bot 0c2104
	    = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
Packit Bot 0c2104
	  fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
Packit Bot 0c2104
	  value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
Packit Bot 0c2104
	}
Packit Bot 0c2104
Packit Bot 0c2104
#ifdef SHARED
Packit Bot 0c2104
      /* Auditing checkpoint: we have a new binding.  Provide the
Packit Bot 0c2104
	 auditing libraries the possibility to change the value and
Packit Bot 0c2104
	 tell us whether further auditing is wanted.  */
Packit Bot 0c2104
      if (__glibc_unlikely (GLRO(dl_naudit) > 0))
Packit Bot 0c2104
	{
Packit Bot 0c2104
	  const char *strtab = (const char *) D_PTR (result,
Packit Bot 0c2104
						     l_info[DT_STRTAB]);
Packit Bot 0c2104
	  /* Compute index of the symbol entry in the symbol table of
Packit Bot 0c2104
	     the DSO with the definition.  */
Packit Bot 0c2104
	  unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
Packit Bot 0c2104
							 l_info[DT_SYMTAB]));
Packit Bot 0c2104
Packit Bot 0c2104
	  if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
Packit Bot 0c2104
	    {
Packit Bot 0c2104
	      unsigned int altvalue = 0;
Packit Bot 0c2104
	      struct audit_ifaces *afct = GLRO(dl_audit);
Packit Bot 0c2104
	      /* Synthesize a symbol record where the st_value field is
Packit Bot 0c2104
		 the result.  */
Packit Bot 0c2104
	      ElfW(Sym) sym = *ref;
Packit Bot 0c2104
	      sym.st_value = (ElfW(Addr)) value;
Packit Bot 0c2104
Packit Bot 0c2104
	      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit Bot 0c2104
		{
Packit Bot 0c2104
		  if (afct->symbind != NULL
Packit Bot 0c2104
		      && ((match->l_audit[cnt].bindflags & LA_FLG_BINDFROM)
Packit Bot 0c2104
			  != 0
Packit Bot 0c2104
			  || ((result->l_audit[cnt].bindflags & LA_FLG_BINDTO)
Packit Bot 0c2104
			      != 0)))
Packit Bot 0c2104
		    {
Packit Bot 0c2104
		      unsigned int flags = altvalue | LA_SYMB_DLSYM;
Packit Bot 0c2104
		      uintptr_t new_value
Packit Bot 0c2104
			= afct->symbind (&sym, ndx,
Packit Bot 0c2104
					 &match->l_audit[cnt].cookie,
Packit Bot 0c2104
					 &result->l_audit[cnt].cookie,
Packit Bot 0c2104
					 &flags, strtab + ref->st_name);
Packit Bot 0c2104
		      if (new_value != (uintptr_t) sym.st_value)
Packit Bot 0c2104
			{
Packit Bot 0c2104
			  altvalue = LA_SYMB_ALTVALUE;
Packit Bot 0c2104
			  sym.st_value = new_value;
Packit Bot 0c2104
			}
Packit Bot 0c2104
		    }
Packit Bot 0c2104
Packit Bot 0c2104
		  afct = afct->next;
Packit Bot 0c2104
		}
Packit Bot 0c2104
Packit Bot 0c2104
	      value = (void *) sym.st_value;
Packit Bot 0c2104
	    }
Packit Bot 0c2104
	}
Packit Bot 0c2104
#endif
Packit Bot 0c2104
Packit Bot 0c2104
      return value;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_dl_vsym (void *handle, const char *name, const char *version, void *who)
Packit 6c4009
{
Packit 6c4009
  struct r_found_version vers;
Packit 6c4009
Packit 6c4009
  /* Compute hash value to the version string.  */
Packit 6c4009
  vers.name = version;
Packit 6c4009
  vers.hidden = 1;
Packit 6c4009
  vers.hash = _dl_elf_hash (version);
Packit 6c4009
  /* We don't have a specific file where the symbol can be found.  */
Packit 6c4009
  vers.filename = NULL;
Packit 6c4009
Packit 6c4009
  return do_sym (handle, name, who, &vers, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_dl_sym (void *handle, const char *name, void *who)
Packit 6c4009
{
Packit 6c4009
  return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
Packit 6c4009
}