]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Treat STV_HIDDEN and STV_INTERNAL symbols as STB_LOCAL
authorMaciej W. Rozycki <macro@imgtec.com>
Sat, 7 May 2016 01:29:54 +0000 (02:29 +0100)
committerMaciej W. Rozycki <macro@imgtec.com>
Fri, 1 Jul 2016 22:48:52 +0000 (23:48 +0100)
In a reference to PR ld/19908 make ld.so respect symbol export classes
aka visibility and treat STV_HIDDEN and STV_INTERNAL symbols as local,
preventing such symbols from preempting exported symbols.

According to the ELF gABI[1] neither STV_HIDDEN nor STV_INTERNAL symbols
are supposed to be present in linked binaries:

"A hidden symbol contained in a relocatable object must be either
removed or converted to STB_LOCAL binding by the link-editor when the
relocatable object is included in an executable file or shared object."

"An internal symbol contained in a relocatable object must be either
removed or converted to STB_LOCAL binding by the link-editor when the
relocatable object is included in an executable file or shared object."

however some GNU binutils versions produce such symbols in some cases.
PR ld/19908 is one and we also have this note in scripts/abilist.awk:

so clearly there is linked code out there which contains such symbols
which is prone to symbol table misinterpretation, and it'll be more
productive if we handle this gracefully, under the Robustness Principle:
"be liberal in what you accept, and conservative in what you produce",
especially as this is a simple (STV_HIDDEN|STV_INTERNAL) => STB_LOCAL
mapping.

References:

[1] "System V Application Binary Interface - DRAFT - 24 April 2001",
    The Santa Cruz Operation, Inc., "Symbol Table",
    <http://www.sco.com/developers/gabi/2001-04-24/ch4.symtab.html>

* sysdeps/generic/ldsodefs.h
(dl_symbol_visibility_binds_local_p): New inline function.
* elf/dl-addr.c (determine_info): Treat hidden and internal
symbols as local.
* elf/dl-lookup.c (do_lookup_x): Likewise.
* elf/dl-reloc.c (RESOLVE_MAP): Likewise.

ChangeLog
elf/dl-addr.c
elf/dl-lookup.c
elf/dl-reloc.c
sysdeps/generic/ldsodefs.h

index a7ca1ff16e9c9a79f7fac2cf67cb6de17ac3d276..29a92f5a5bfc81830b656f105c7a3f147491586a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-07-01  Maciej W. Rozycki  <macro@imgtec.com>
+
+       * sysdeps/generic/ldsodefs.h
+       (dl_symbol_visibility_binds_local_p): New inline function.
+       * elf/dl-addr.c (determine_info): Treat hidden and internal
+       symbols as local.
+       * elf/dl-lookup.c (do_lookup_x): Likewise.
+       * elf/dl-reloc.c (RESOLVE_MAP): Likewise.
+
 2016-07-01  Aurelien Jarno  <aurelien@aurel32.net>
 
        * sparc/sparc32/sparcv9/fpu/s_nearbyint.S (__nearbyint): Trigger an
index 291ff5581666e1c560dc9737f683fe4e888624a0..1b16a58cedaa534318aa33039181350c40c69db2 100644 (file)
@@ -88,6 +88,7 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
       for (; (void *) symtab < (void *) symtabend; ++symtab)
        if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
             || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
+           && __glibc_likely (!dl_symbol_visibility_binds_local_p (symtab))
            && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
            && (symtab->st_shndx != SHN_UNDEF
                || symtab->st_value != 0)
index 6d299c1097c69733979a4027c1f6312962aacaa5..52c994e16c1605cc42fbb21e9387bde12fc5faab 100644 (file)
@@ -516,6 +516,10 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
 #endif
            }
 
+         /* Hidden and internal symbols are local, ignore them.  */
+         if (__glibc_unlikely (dl_symbol_visibility_binds_local_p (sym)))
+           goto skip;
+
          switch (ELFW(ST_BIND) (sym->st_info))
            {
            case STB_WEAK:
index 14709f960da9ce3234d8a460062b61e128475855..42bddc1e2c64626640fdfa05d1214d6c084971ce 100644 (file)
@@ -233,7 +233,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
 
     /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code.  */
 #define RESOLVE_MAP(ref, version, r_type) \
-    (ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL                            \
+    ((ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL                           \
+      && __glibc_likely (!dl_symbol_visibility_binds_local_p (*ref)))        \
      ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0)               \
         && elf_machine_type_class (r_type) == l->l_lookup_cache.type_class)  \
        ? (bump_num_cache_relocations (),                                     \
index ddec0be12c825ab1c5c03690f36bb991b213556c..f68fdf4501821dfcaf0c814afecb9bcb3aaf7c87 100644 (file)
@@ -88,6 +88,19 @@ typedef struct link_map *lookup_t;
        || (ADDR) < (L)->l_addr + (SYM)->st_value + (SYM)->st_size)     \
    && ((MATCHSYM) == NULL || (MATCHSYM)->st_value < (SYM)->st_value))
 
+/* According to the ELF gABI no STV_HIDDEN or STV_INTERNAL symbols are
+   expected to be present in dynamic symbol tables as they should have
+   been either removed or converted to STB_LOCAL binding by the static
+   linker.  However some GNU binutils versions produce such symbols in
+   some cases.  To prevent such symbols present in a buggy binary from
+   preempting global symbols we filter them out with this predicate.  */
+static __always_inline bool
+dl_symbol_visibility_binds_local_p (const ElfW(Sym) *sym)
+{
+  return (ELFW(ST_VISIBILITY) (sym->st_other) == STV_HIDDEN
+         || ELFW(ST_VISIBILITY) (sym->st_other) == STV_INTERNAL);
+}
+
 /* Unmap a loaded object, called by _dl_close (). */
 #ifndef DL_UNMAP_IS_SPECIAL
 # define DL_UNMAP(map) _dl_unmap_segments (map)