| commit c76147afe917ef7d309ee893f8f017a3c2934aac |
| Author: Florian Weimer <fweimer@redhat.com> |
| Date: Sat Feb 8 15:00:28 2020 +0100 |
| |
| elf: Extract _dl_sym_post, _dl_sym_find_caller_map from elf/dl-sym.c |
| |
| The definitions are moved into a new file, elf/dl-sym-post.h, so that |
| this code can be used by the dynamic loader as well. |
| |
| Reviewed-by: Carlos O'Donell <carlos@redhat.com> |
| |
| diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h |
| new file mode 100644 |
| index 0000000000000000..4c4f574633497789 |
| |
| |
| @@ -0,0 +1,106 @@ |
| +/* Post-processing of a symbol produced by dlsym, dlvsym. |
| + Copyright (C) 1999-2020 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| + |
| +/* Return the link map containing the caller address. */ |
| +static struct link_map * |
| +_dl_sym_find_caller_link_map (ElfW(Addr) caller) |
| +{ |
| + struct link_map *l = _dl_find_dso_for_object (caller); |
| + if (l != NULL) |
| + return l; |
| + else |
| + /* If the address is not recognized the call comes from the main |
| + program (we hope). */ |
| + return GL(dl_ns)[LM_ID_BASE]._ns_loaded; |
| +} |
| + |
| +/* Translates RESULT, *REF, VALUE into a symbol address from the point |
| + of view of MATCH. Performs IFUNC resolution and auditing if |
| + necessary. If MATCH is NULL, CALLER is used to determine it. */ |
| +static void * |
| +_dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value, |
| + ElfW(Addr) caller, struct link_map *match) |
| +{ |
| + /* Resolve indirect function address. */ |
| + if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)) |
| + { |
| + DL_FIXUP_VALUE_TYPE fixup |
| + = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value); |
| + fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup)); |
| + value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup); |
| + } |
| + |
| +#ifdef SHARED |
| + /* Auditing checkpoint: we have a new binding. Provide the |
| + auditing libraries the possibility to change the value and |
| + tell us whether further auditing is wanted. */ |
| + if (__glibc_unlikely (GLRO(dl_naudit) > 0)) |
| + { |
| + const char *strtab = (const char *) D_PTR (result, |
| + l_info[DT_STRTAB]); |
| + /* Compute index of the symbol entry in the symbol table of |
| + the DSO with the definition. */ |
| + unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, |
| + l_info[DT_SYMTAB])); |
| + |
| + if (match == NULL) |
| + match = _dl_sym_find_caller_link_map (caller); |
| + |
| + if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) |
| + { |
| + unsigned int altvalue = 0; |
| + struct audit_ifaces *afct = GLRO(dl_audit); |
| + /* Synthesize a symbol record where the st_value field is |
| + the result. */ |
| + ElfW(Sym) sym = *ref; |
| + sym.st_value = (ElfW(Addr)) value; |
| + |
| + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
| + { |
| + struct auditstate *match_audit |
| + = link_map_audit_state (match, cnt); |
| + struct auditstate *result_audit |
| + = link_map_audit_state (result, cnt); |
| + if (afct->symbind != NULL |
| + && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 |
| + || ((result_audit->bindflags & LA_FLG_BINDTO) |
| + != 0))) |
| + { |
| + unsigned int flags = altvalue | LA_SYMB_DLSYM; |
| + uintptr_t new_value |
| + = afct->symbind (&sym, ndx, |
| + &match_audit->cookie, |
| + &result_audit->cookie, |
| + &flags, strtab + ref->st_name); |
| + if (new_value != (uintptr_t) sym.st_value) |
| + { |
| + altvalue = LA_SYMB_ALTVALUE; |
| + sym.st_value = new_value; |
| + } |
| + } |
| + |
| + afct = afct->next; |
| + } |
| + |
| + value = (void *) sym.st_value; |
| + } |
| + } |
| +#endif |
| + return value; |
| +} |
| diff --git a/elf/dl-sym.c b/elf/dl-sym.c |
| index b133850a3c6657a4..5698fd7874a0ce48 100644 |
| |
| |
| @@ -28,6 +28,7 @@ |
| #include <sysdep-cancel.h> |
| #include <dl-tls.h> |
| #include <dl-irel.h> |
| +#include <dl-sym-post.h> |
| |
| |
| #ifdef SHARED |
| @@ -80,19 +81,6 @@ call_dl_lookup (void *ptr) |
| args->flags, NULL); |
| } |
| |
| -/* Return the link map containing the caller address. */ |
| -static inline struct link_map * |
| -find_caller_link_map (ElfW(Addr) caller) |
| -{ |
| - struct link_map *l = _dl_find_dso_for_object (caller); |
| - if (l != NULL) |
| - return l; |
| - else |
| - /* If the address is not recognized the call comes from the main |
| - program (we hope). */ |
| - return GL(dl_ns)[LM_ID_BASE]._ns_loaded; |
| -} |
| - |
| static void * |
| do_sym (void *handle, const char *name, void *who, |
| struct r_found_version *vers, int flags) |
| @@ -106,7 +94,7 @@ do_sym (void *handle, const char *name, void *who, |
| |
| if (handle == RTLD_DEFAULT) |
| { |
| - match = find_caller_link_map (caller); |
| + match = _dl_sym_find_caller_link_map (caller); |
| |
| /* Search the global scope. We have the simple case where |
| we look up in the scope of an object which was part of |
| @@ -140,7 +128,7 @@ do_sym (void *handle, const char *name, void *who, |
| } |
| else if (handle == RTLD_NEXT) |
| { |
| - match = find_caller_link_map (caller); |
| + match = _dl_sym_find_caller_link_map (caller); |
| |
| if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded)) |
| { |
| @@ -179,73 +167,7 @@ RTLD_NEXT used in code not dynamically loaded")); |
| #endif |
| value = DL_SYMBOL_ADDRESS (result, ref); |
| |
| - /* Resolve indirect function address. */ |
| - if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC)) |
| - { |
| - DL_FIXUP_VALUE_TYPE fixup |
| - = DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value); |
| - fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup)); |
| - value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup); |
| - } |
| - |
| -#ifdef SHARED |
| - /* Auditing checkpoint: we have a new binding. Provide the |
| - auditing libraries the possibility to change the value and |
| - tell us whether further auditing is wanted. */ |
| - if (__glibc_unlikely (GLRO(dl_naudit) > 0)) |
| - { |
| - const char *strtab = (const char *) D_PTR (result, |
| - l_info[DT_STRTAB]); |
| - /* Compute index of the symbol entry in the symbol table of |
| - the DSO with the definition. */ |
| - unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, |
| - l_info[DT_SYMTAB])); |
| - |
| - if (match == NULL) |
| - match = find_caller_link_map (caller); |
| - |
| - if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) |
| - { |
| - unsigned int altvalue = 0; |
| - struct audit_ifaces *afct = GLRO(dl_audit); |
| - /* Synthesize a symbol record where the st_value field is |
| - the result. */ |
| - ElfW(Sym) sym = *ref; |
| - sym.st_value = (ElfW(Addr)) value; |
| - |
| - for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) |
| - { |
| - struct auditstate *match_audit |
| - = link_map_audit_state (match, cnt); |
| - struct auditstate *result_audit |
| - = link_map_audit_state (result, cnt); |
| - if (afct->symbind != NULL |
| - && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 |
| - || ((result_audit->bindflags & LA_FLG_BINDTO) |
| - != 0))) |
| - { |
| - unsigned int flags = altvalue | LA_SYMB_DLSYM; |
| - uintptr_t new_value |
| - = afct->symbind (&sym, ndx, |
| - &match_audit->cookie, |
| - &result_audit->cookie, |
| - &flags, strtab + ref->st_name); |
| - if (new_value != (uintptr_t) sym.st_value) |
| - { |
| - altvalue = LA_SYMB_ALTVALUE; |
| - sym.st_value = new_value; |
| - } |
| - } |
| - |
| - afct = afct->next; |
| - } |
| - |
| - value = (void *) sym.st_value; |
| - } |
| - } |
| -#endif |
| - |
| - return value; |
| + return _dl_sym_post (result, ref, value, caller, match); |
| } |
| |
| return NULL; |