Blame elf/dl-sym-post.h

Packit Service 3c8405
/* Post-processing of a symbol produced by dlsym, dlvsym.
Packit Service 3c8405
   Copyright (C) 1999-2020 Free Software Foundation, Inc.
Packit Service 3c8405
   This file is part of the GNU C Library.
Packit Service 3c8405
Packit Service 3c8405
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 3c8405
   modify it under the terms of the GNU Lesser General Public
Packit Service 3c8405
   License as published by the Free Software Foundation; either
Packit Service 3c8405
   version 2.1 of the License, or (at your option) any later version.
Packit Service 3c8405
Packit Service 3c8405
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 3c8405
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 3c8405
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 3c8405
   Lesser General Public License for more details.
Packit Service 3c8405
Packit Service 3c8405
   You should have received a copy of the GNU Lesser General Public
Packit Service 3c8405
   License along with the GNU C Library; if not, see
Packit Service 3c8405
   <https://www.gnu.org/licenses/>.  */
Packit Service 3c8405
Packit Service 3c8405
Packit Service 3c8405
/* Return the link map containing the caller address.  */
Packit Service 3c8405
static struct link_map *
Packit Service 3c8405
_dl_sym_find_caller_link_map (ElfW(Addr) caller)
Packit Service 3c8405
{
Packit Service 3c8405
  struct link_map *l = _dl_find_dso_for_object (caller);
Packit Service 3c8405
  if (l != NULL)
Packit Service 3c8405
    return l;
Packit Service 3c8405
  else
Packit Service 3c8405
    /* If the address is not recognized the call comes from the main
Packit Service 3c8405
       program (we hope).  */
Packit Service 3c8405
    return GL(dl_ns)[LM_ID_BASE]._ns_loaded;
Packit Service 3c8405
}
Packit Service 3c8405
Packit Service 3c8405
/* Translates RESULT, *REF, VALUE into a symbol address from the point
Packit Service 3c8405
   of view of MATCH.  Performs IFUNC resolution and auditing if
Packit Service 3c8405
   necessary.  If MATCH is NULL, CALLER is used to determine it.  */
Packit Service 3c8405
static void *
Packit Service 3c8405
_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
Packit Service 3c8405
              ElfW(Addr) caller, struct link_map *match)
Packit Service 3c8405
{
Packit Service 3c8405
  /* Resolve indirect function address.  */
Packit Service 3c8405
  if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
Packit Service 3c8405
    {
Packit Service 3c8405
      DL_FIXUP_VALUE_TYPE fixup
Packit Service 3c8405
        = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
Packit Service 3c8405
      fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
Packit Service 3c8405
      value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
Packit Service 3c8405
    }
Packit Service 3c8405
Packit Service 3c8405
#ifdef SHARED
Packit Service 3c8405
  /* Auditing checkpoint: we have a new binding.  Provide the
Packit Service 3c8405
     auditing libraries the possibility to change the value and
Packit Service 3c8405
     tell us whether further auditing is wanted.  */
Packit Service 3c8405
  if (__glibc_unlikely (GLRO(dl_naudit) > 0))
Packit Service 3c8405
    {
Packit Service 3c8405
      const char *strtab = (const char *) D_PTR (result,
Packit Service 3c8405
                                                 l_info[DT_STRTAB]);
Packit Service 3c8405
      /* Compute index of the symbol entry in the symbol table of
Packit Service 3c8405
         the DSO with the definition.  */
Packit Service 3c8405
      unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result,
Packit Service 3c8405
                                                     l_info[DT_SYMTAB]));
Packit Service 3c8405
Packit Service 3c8405
      if (match == NULL)
Packit Service 3c8405
        match = _dl_sym_find_caller_link_map (caller);
Packit Service 3c8405
Packit Service 3c8405
      if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0)
Packit Service 3c8405
        {
Packit Service 3c8405
          unsigned int altvalue = 0;
Packit Service 3c8405
          struct audit_ifaces *afct = GLRO(dl_audit);
Packit Service 3c8405
          /* Synthesize a symbol record where the st_value field is
Packit Service 3c8405
             the result.  */
Packit Service 3c8405
          ElfW(Sym) sym = *ref;
Packit Service 3c8405
          sym.st_value = (ElfW(Addr)) value;
Packit Service 3c8405
Packit Service 3c8405
          for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
Packit Service 3c8405
            {
Packit Service 3c8405
              struct auditstate *match_audit
Packit Service 3c8405
                = link_map_audit_state (match, cnt);
Packit Service 3c8405
              struct auditstate *result_audit
Packit Service 3c8405
                = link_map_audit_state (result, cnt);
Packit Service 3c8405
              if (afct->symbind != NULL
Packit Service 3c8405
                  && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0
Packit Service 3c8405
                      || ((result_audit->bindflags & LA_FLG_BINDTO)
Packit Service 3c8405
                          != 0)))
Packit Service 3c8405
                {
Packit Service 3c8405
                  unsigned int flags = altvalue | LA_SYMB_DLSYM;
Packit Service 3c8405
                  uintptr_t new_value
Packit Service 3c8405
                    = afct->symbind (&sym, ndx,
Packit Service 3c8405
                                     &match_audit->cookie,
Packit Service 3c8405
                                     &result_audit->cookie,
Packit Service 3c8405
                                     &flags, strtab + ref->st_name);
Packit Service 3c8405
                  if (new_value != (uintptr_t) sym.st_value)
Packit Service 3c8405
                    {
Packit Service 3c8405
                      altvalue = LA_SYMB_ALTVALUE;
Packit Service 3c8405
                      sym.st_value = new_value;
Packit Service 3c8405
                    }
Packit Service 3c8405
                }
Packit Service 3c8405
Packit Service 3c8405
              afct = afct->next;
Packit Service 3c8405
            }
Packit Service 3c8405
Packit Service 3c8405
          value = (void *) sym.st_value;
Packit Service 3c8405
        }
Packit Service 3c8405
    }
Packit Service 3c8405
#endif
Packit Service 3c8405
  return value;
Packit Service 3c8405
}