This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed, PATCH] PR ld/18841: Data relocations with IFUNC symbols can lead to segfault


elf_XXX_reloc_type_class should return reloc_class_ifunc for relocation
against STT_GNU_IFUNC symbol.

bfd/

	PR ld/18841
	* elf-bfd.h (elf_link_hash_table): Add dynsym.
	* elf32-i386.c (elf_i386_reloc_type_class): Return
	reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol.
	* elf64-x86-64.c (elf_x86_64_reloc_type_class): Likewise.
	* elflink.c (_bfd_elf_link_create_dynamic_sections): Set dynsym.
	(bfd_elf_size_dynsym_hash_dynstr): Use dynsym.
	(elf_final_link_info): Remove dynsym_sec.
	(elf_link_output_extsym): Replace dynsym_sec with dynsym.
	(bfd_elf_final_link): Remove reference to dynsym_sec.  Replace
	dynsym_sec with dynsym.

ld/testsuite/

	PR ld/18841
	* ld-ifunc/ifunc.exp: Add a test for PR ld/18841.
	* ld-ifunc/pr18841.out: New file.
	* ld-ifunc/pr18841a.c: Likewise.
	* ld-ifunc/pr18841b.c: Likewise.
---
 bfd/ChangeLog                     | 14 ++++++++++++++
 bfd/elf-bfd.h                     |  1 +
 bfd/elf32-i386.c                  | 19 ++++++++++++++++++-
 bfd/elf64-x86-64.c                | 19 ++++++++++++++++++-
 bfd/elflink.c                     | 21 ++++++++++-----------
 ld/testsuite/ChangeLog            |  8 ++++++++
 ld/testsuite/ld-ifunc/ifunc.exp   | 16 ++++++++++++++++
 ld/testsuite/ld-ifunc/pr18841.out |  1 +
 ld/testsuite/ld-ifunc/pr18841a.c  | 12 ++++++++++++
 ld/testsuite/ld-ifunc/pr18841b.c  | 21 +++++++++++++++++++++
 10 files changed, 119 insertions(+), 13 deletions(-)
 create mode 100644 ld/testsuite/ld-ifunc/pr18841.out
 create mode 100644 ld/testsuite/ld-ifunc/pr18841a.c
 create mode 100644 ld/testsuite/ld-ifunc/pr18841b.c

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 14290ab..c0fbbe9 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -7,6 +7,20 @@
 
 2015-08-18  H.J. Lu  <hongjiu.lu@intel.com>
 
+	PR ld/18841
+	* elf-bfd.h (elf_link_hash_table): Add dynsym.
+	* elf32-i386.c (elf_i386_reloc_type_class): Return
+	reloc_class_ifunc for relocation against STT_GNU_IFUNC symbol.
+	* elf64-x86-64.c (elf_x86_64_reloc_type_class): Likewise.
+	* elflink.c (_bfd_elf_link_create_dynamic_sections): Set dynsym.
+	(bfd_elf_size_dynsym_hash_dynstr): Use dynsym.
+	(elf_final_link_info): Remove dynsym_sec.
+	(elf_link_output_extsym): Replace dynsym_sec with dynsym.
+	(bfd_elf_final_link): Remove reference to dynsym_sec.  Replace
+	dynsym_sec with dynsym.
+
+2015-08-18  H.J. Lu  <hongjiu.lu@intel.com>
+
 	* bfd/aoutx.h: Replace shared, executable, relocatable and pie
 	fields with bfd_link_executable, bfd_link_dll,
 	bfd_link_relocatable, bfd_link_pic and bfd_link_pie.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index f5a1f45..e0e372f 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -595,6 +595,7 @@ struct elf_link_hash_table
   asection *iplt;
   asection *irelplt;
   asection *irelifunc;
+  asection *dynsym;
 };
 
 /* Look up an entry in an ELF linker hash table.  */
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 507eecf..7642d0f 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -4973,10 +4973,27 @@ elf_i386_finish_local_dynamic_symbol (void **slot, void *inf)
    dynamic linker, before writing them out.  */
 
 static enum elf_reloc_type_class
-elf_i386_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+elf_i386_reloc_type_class (const struct bfd_link_info *info,
 			   const asection *rel_sec ATTRIBUTE_UNUSED,
 			   const Elf_Internal_Rela *rela)
 {
+  bfd *abfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  unsigned long r_symndx = ELF32_R_SYM (rela->r_info);
+  Elf_Internal_Sym sym;
+
+  if (htab->dynsym == NULL
+      || !bed->s->swap_symbol_in (abfd,
+				  (htab->dynsym->contents
+				   + r_symndx * sizeof (Elf32_External_Sym)),
+				  0, &sym))
+    abort ();
+
+  /* Check relocation against STT_GNU_IFUNC symbol.  */
+  if (ELF32_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+    return reloc_class_ifunc;
+
   switch (ELF32_R_TYPE (rela->r_info))
     {
     case R_386_RELATIVE:
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 987ce0e..f15d33e 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -5464,10 +5464,27 @@ elf_x86_64_finish_local_dynamic_symbol (void **slot, void *inf)
    dynamic linker, before writing them out.  */
 
 static enum elf_reloc_type_class
-elf_x86_64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+elf_x86_64_reloc_type_class (const struct bfd_link_info *info,
 			     const asection *rel_sec ATTRIBUTE_UNUSED,
 			     const Elf_Internal_Rela *rela)
 {
+  bfd *abfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct elf_x86_64_link_hash_table *htab = elf_x86_64_hash_table (info);
+  unsigned long r_symndx = htab->r_sym (rela->r_info);
+  Elf_Internal_Sym sym;
+
+  if (htab->elf.dynsym == NULL
+      || !bed->s->swap_symbol_in (abfd,
+				  (htab->elf.dynsym->contents
+				   + r_symndx * bed->s->sizeof_sym),
+				  0, &sym))
+    abort ();
+
+  /* Check relocation against STT_GNU_IFUNC symbol.  */
+  if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+    return reloc_class_ifunc;
+
   switch ((int) ELF32_R_TYPE (rela->r_info))
     {
     case R_X86_64_RELATIVE:
diff --git a/bfd/elflink.c b/bfd/elflink.c
index e4a9ced..7f04271 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -279,6 +279,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
     return FALSE;
+  elf_hash_table (info)->dynsym = s;
 
   s = bfd_make_section_anyway_with_flags (abfd, ".dynstr",
 					  flags | SEC_READONLY);
@@ -6545,7 +6546,7 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
 	 the final symbol table, because until then we do not know the
 	 correct value to give the symbols.  We built the .dynstr
 	 section as we went along in elf_link_add_object_symbols.  */
-      s = bfd_get_linker_section (dynobj, ".dynsym");
+      s = elf_hash_table (info)->dynsym;
       BFD_ASSERT (s != NULL);
       s->size = dynsymcount * bed->s->sizeof_sym;
 
@@ -7541,8 +7542,6 @@ struct elf_final_link_info
   bfd *output_bfd;
   /* Symbol string table.  */
   struct elf_strtab_hash *symstrtab;
-  /* .dynsym section.  */
-  asection *dynsym_sec;
   /* .hash section.  */
   asection *hash_sec;
   /* symbol version section (.gnu.version).  */
@@ -9314,7 +9313,7 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
   /* If this symbol should be put in the .dynsym section, then put it
      there now.  We already know the symbol index.  We also fill in
      the entry in the .hash section.  */
-  if (flinfo->dynsym_sec != NULL
+  if (elf_hash_table (flinfo->info)->dynsym != NULL
       && h->dynindx != -1
       && elf_hash_table (flinfo->info)->dynamic_sections_created)
     {
@@ -9344,7 +9343,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
 	}
 
       sym.st_name = h->dynstr_index;
-      esym = flinfo->dynsym_sec->contents + h->dynindx * bed->s->sizeof_sym;
+      esym = (elf_hash_table (flinfo->info)->dynsym->contents
+	      + h->dynindx * bed->s->sizeof_sym);
       if (!check_dynsym (flinfo->output_bfd, &sym))
 	{
 	  eoinfo->failed = TRUE;
@@ -10868,13 +10868,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   if (! dynamic)
     {
-      flinfo.dynsym_sec = NULL;
       flinfo.hash_sec = NULL;
       flinfo.symver_sec = NULL;
     }
   else
     {
-      flinfo.dynsym_sec = bfd_get_linker_section (dynobj, ".dynsym");
       flinfo.hash_sec = bfd_get_linker_section (dynobj, ".hash");
       /* Note that dynsym_sec can be NULL (on VMS).  */
       flinfo.symver_sec = bfd_get_linker_section (dynobj, ".gnu.version");
@@ -11407,11 +11405,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   symtab_hdr->sh_info = bfd_get_symcount (abfd);
 
   if (dynamic
-      && flinfo.dynsym_sec != NULL
-      && flinfo.dynsym_sec->output_section != bfd_abs_section_ptr)
+      && elf_hash_table (info)->dynsym != NULL
+      && (elf_hash_table (info)->dynsym->output_section
+	  != bfd_abs_section_ptr))
     {
       Elf_Internal_Sym sym;
-      bfd_byte *dynsym = flinfo.dynsym_sec->contents;
+      bfd_byte *dynsym = elf_hash_table (info)->dynsym->contents;
       long last_local = 0;
 
       /* Write out the section symbols for the output sections.  */
@@ -11484,7 +11483,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	    }
 	}
 
-      elf_section_data (flinfo.dynsym_sec->output_section)->this_hdr.sh_info =
+      elf_section_data (elf_hash_table (info)->dynsym->output_section)->this_hdr.sh_info =
 	last_local + 1;
     }
 
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 5ae5cd4..b8546d0 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2015-08-18  H.J. Lu  <hongjiu.lu@intel.com>
+
+	PR ld/18841
+	* ld-ifunc/ifunc.exp: Add a test for PR ld/18841.
+	* ld-ifunc/pr18841.out: New file.
+	* ld-ifunc/pr18841a.c: Likewise.
+	* ld-ifunc/pr18841b.c: Likewise.
+
 2015-08-13  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/18801
diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp
index 498cb2d..b0f6de0 100644
--- a/ld/testsuite/ld-ifunc/ifunc.exp
+++ b/ld/testsuite/ld-ifunc/ifunc.exp
@@ -472,6 +472,14 @@ run_cc_link_tests [list \
 	{} \
 	"libpr18808.so" \
     ] \
+    [list \
+	"Build libpr18841.so" \
+	"-shared" \
+	"-fPIC -O0 -g" \
+	{ pr18841b.c } \
+	{} \
+	"libpr18841.so" \
+    ] \
 ]
 
 run_ld_link_exec_tests [] [list \
@@ -483,4 +491,12 @@ run_ld_link_exec_tests [] [list \
 	"pr18808" \
 	"pr18808.out" \
     ] \
+    [list \
+	"Run pr18841" \
+	"tmpdir/libpr18841.so" \
+	"" \
+	{ pr18841a.c } \
+	"pr18841" \
+	"pr18841.out" \
+    ] \
 ]
diff --git a/ld/testsuite/ld-ifunc/pr18841.out b/ld/testsuite/ld-ifunc/pr18841.out
new file mode 100644
index 0000000..d86bac9
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr18841.out
@@ -0,0 +1 @@
+OK
diff --git a/ld/testsuite/ld-ifunc/pr18841a.c b/ld/testsuite/ld-ifunc/pr18841a.c
new file mode 100644
index 0000000..72179d2
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr18841a.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void test(void);
+
+void zoo(){}
+
+int main()
+{
+  test();
+  printf("OK\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-ifunc/pr18841b.c b/ld/testsuite/ld-ifunc/pr18841b.c
new file mode 100644
index 0000000..1e87469
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr18841b.c
@@ -0,0 +1,21 @@
+void foo() __attribute__((ifunc("resolve_foo")));
+
+static void foo_impl() {}
+
+extern void abort (void);
+void test()
+{
+  void (*pg)(void) = foo;
+  if (pg != foo_impl)
+    abort ();
+  pg();
+}
+
+static void* resolve_foo()
+{
+  extern void zoo(void);
+
+  void (*pz)(void) = zoo;
+  pz();
+  return foo_impl;
+}
-- 
2.4.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]