From bce964aa6c777d236fbd641f2bc7bb931cfe4bf3 Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
Date: Sun, 23 Apr 2017 11:03:34 +0930
Subject: [PATCH] PR 21412, get_reloc_section assumes .rel/.rela name for
 SHT_REL/RELA.

This patch fixes an assumption made by code that runs for objcopy and
strip, that SHT_REL/SHR_RELA sections are always named starting with a
.rel/.rela prefix.  I'm also modifying the interface for
elf_backend_get_reloc_section, so any backend function just needs to
handle name mapping.

	PR 21412
	* elf-bfd.h (struct elf_backend_data <get_reloc_section>): Change
	parameters and comment.
	(_bfd_elf_get_reloc_section): Delete.
	(_bfd_elf_plt_get_reloc_section): Declare.
	* elf.c (_bfd_elf_plt_get_reloc_section, elf_get_reloc_section):
	New functions.  Don't blindly skip over assumed .rel/.rela prefix.
	Extracted from..
	(_bfd_elf_get_reloc_section): ..here.  Delete.
	(assign_section_numbers): Call elf_get_reloc_section.
	* elf64-ppc.c (elf_backend_get_reloc_section): Define.
	* elfxx-target.h (elf_backend_get_reloc_section): Update.

Upstream-Status: Backport
CVE: CVE-2017-8393
Signed-off-by: Armin Kuster <akuster@mvista.com>

---
 bfd/ChangeLog      | 15 ++++++++++++++
 bfd/elf-bfd.h      |  8 ++++---
 bfd/elf.c          | 61 +++++++++++++++++++++++++++++++-----------------------
 bfd/elf64-ppc.c    |  1 +
 bfd/elfxx-target.h |  2 +-
 5 files changed, 57 insertions(+), 30 deletions(-)

Index: git/bfd/elf-bfd.h
===================================================================
--- git.orig/bfd/elf-bfd.h
+++ git/bfd/elf-bfd.h
@@ -1322,8 +1322,10 @@ struct elf_backend_data
   bfd_size_type (*maybe_function_sym) (const asymbol *sym, asection *sec,
 				       bfd_vma *code_off);
 
-  /* Return the section which RELOC_SEC applies to.  */
-  asection *(*get_reloc_section) (asection *reloc_sec);
+  /* Given NAME, the name of a relocation section stripped of its
+     .rel/.rela prefix, return the section in ABFD to which the
+     relocations apply.  */
+  asection *(*get_reloc_section) (bfd *abfd, const char *name);
 
   /* Called to set the sh_flags, sh_link and sh_info fields of OSECTION which
      has a type >= SHT_LOOS.  Returns TRUE if the fields were initialised,
@@ -2392,7 +2394,7 @@ extern bfd_boolean _bfd_elf_is_function_
 extern bfd_size_type _bfd_elf_maybe_function_sym (const asymbol *, asection *,
 						  bfd_vma *);
 
-extern asection *_bfd_elf_get_reloc_section (asection *);
+extern asection *_bfd_elf_plt_get_reloc_section (bfd *, const char *);
 
 extern int bfd_elf_get_default_section_type (flagword);
 
Index: git/bfd/elf.c
===================================================================
--- git.orig/bfd/elf.c
+++ git/bfd/elf.c
@@ -3532,17 +3532,39 @@ bfd_elf_set_group_contents (bfd *abfd, a
   H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 }
 
-/* Return the section which RELOC_SEC applies to.  */
+/* Given NAME, the name of a relocation section stripped of its
+   .rel/.rela prefix, return the section in ABFD to which the
+   relocations apply.  */
 
 asection *
-_bfd_elf_get_reloc_section (asection *reloc_sec)
+_bfd_elf_plt_get_reloc_section (bfd *abfd, const char *name)
+{
+  /* If a target needs .got.plt section, relocations in rela.plt/rel.plt
+     section likely apply to .got.plt or .got section.  */
+  if (get_elf_backend_data (abfd)->want_got_plt
+      && strcmp (name, ".plt") == 0)
+    {
+      asection *sec;
+
+      name = ".got.plt";
+      sec = bfd_get_section_by_name (abfd, name);
+      if (sec != NULL)
+	return sec;
+      name = ".got";
+    }
+
+  return bfd_get_section_by_name (abfd, name);
+}
+
+/* Return the section to which RELOC_SEC applies.  */
+
+static asection *
+elf_get_reloc_section (asection *reloc_sec)
 {
   const char *name;
   unsigned int type;
   bfd *abfd;
-
-  if (reloc_sec == NULL)
-    return NULL;
+  const struct elf_backend_data *bed;
 
   type = elf_section_data (reloc_sec)->this_hdr.sh_type;
   if (type != SHT_REL && type != SHT_RELA)
@@ -3550,28 +3572,15 @@ _bfd_elf_get_reloc_section (asection *re
 
   /* We look up the section the relocs apply to by name.  */
   name = reloc_sec->name;
-  if (type == SHT_REL)
-    name += 4;
-  else
-    name += 5;
+  if (strncmp (name, ".rel", 4) != 0)
+    return NULL;
+  name += 4;
+  if (type == SHT_RELA && *name++ != 'a')
+    return NULL;
 
-  /* If a target needs .got.plt section, relocations in rela.plt/rel.plt
-     section apply to .got.plt section.  */
   abfd = reloc_sec->owner;
-  if (get_elf_backend_data (abfd)->want_got_plt
-      && strcmp (name, ".plt") == 0)
-    {
-      /* .got.plt is a linker created input section.  It may be mapped
-	 to some other output section.  Try two likely sections.  */
-      name = ".got.plt";
-      reloc_sec = bfd_get_section_by_name (abfd, name);
-      if (reloc_sec != NULL)
-	return reloc_sec;
-      name = ".got";
-    }
-
-  reloc_sec = bfd_get_section_by_name (abfd, name);
-  return reloc_sec;
+  bed = get_elf_backend_data (abfd);
+  return bed->get_reloc_section (abfd, name);
 }
 
 /* Assign all ELF section numbers.  The dummy first section is handled here
@@ -3833,7 +3842,7 @@ assign_section_numbers (bfd *abfd, struc
 	  if (s != NULL)
 	    d->this_hdr.sh_link = elf_section_data (s)->this_idx;
 
-	  s = get_elf_backend_data (abfd)->get_reloc_section (sec);
+	  s = elf_get_reloc_section (sec);
 	  if (s != NULL)
 	    {
 	      d->this_hdr.sh_info = elf_section_data (s)->this_idx;
Index: git/bfd/elf64-ppc.c
===================================================================
--- git.orig/bfd/elf64-ppc.c
+++ git/bfd/elf64-ppc.c
@@ -121,6 +121,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_special_sections	      ppc64_elf_special_sections
 #define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
 #define elf_backend_merge_symbol	      ppc64_elf_merge_symbol
+#define elf_backend_get_reloc_section	      bfd_get_section_by_name
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
Index: git/bfd/elfxx-target.h
===================================================================
--- git.orig/bfd/elfxx-target.h
+++ git/bfd/elfxx-target.h
@@ -706,7 +706,7 @@
 #endif
 
 #ifndef elf_backend_get_reloc_section
-#define elf_backend_get_reloc_section _bfd_elf_get_reloc_section
+#define elf_backend_get_reloc_section _bfd_elf_plt_get_reloc_section
 #endif
 
 #ifndef elf_backend_copy_special_section_fields
Index: git/bfd/ChangeLog
===================================================================
--- git.orig/bfd/ChangeLog
+++ git/bfd/ChangeLog
@@ -1,3 +1,18 @@
+2017-04-23  Alan Modra  <amodra@gmail.com>
+ 
+       PR 21412
+       * elf-bfd.h (struct elf_backend_data <get_reloc_section>): Change
+       parameters and comment.
+       (_bfd_elf_get_reloc_section): Delete.
+       (_bfd_elf_plt_get_reloc_section): Declare.
+       * elf.c (_bfd_elf_plt_get_reloc_section, elf_get_reloc_section):
+       New functions.  Don't blindly skip over assumed .rel/.rela prefix.
+       Extracted from..
+       (_bfd_elf_get_reloc_section): ..here.  Delete.
+       (assign_section_numbers): Call elf_get_reloc_section.
+       * elf64-ppc.c (elf_backend_get_reloc_section): Define.
+       * elfxx-target.h (elf_backend_get_reloc_section): Update.
+
 2017-04-04  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/21342
