public inbox for binutils-cvs@sourceware.org
 help / color / mirror / Atom feed
* [binutils-gdb] The fuzzers have found the reloc special functions in coff-aarch64.c
@ 2023-01-19  7:14 Alan Modra
  0 siblings, 0 replies; only message in thread
From: Alan Modra @ 2023-01-19  7:14 UTC (permalink / raw)
  To: bfd-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=066bd434118044487e69a9fbc5cacdee60326595

commit 066bd434118044487e69a9fbc5cacdee60326595
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Jan 17 21:53:00 2023 +1030

    The fuzzers have found the reloc special functions in coff-aarch64.c
    
    All of them need a bfd_reloc_offset_in_range check before accessing
    data + reloc_entry->address.  This patch adds the missing checks and
    sanity checks reloc offsets in coff_pe_aarch64_relocate_section too.
    
    All of them also need changing to support objdump -W calls to
    bfd_simple_get_relocated_section_contents.  At least, secrel_reloc
    needs the support, the others might not be present in dwarf debug
    sections.
    
            * coff-aarch64.c (coff_aarch64_rel21_reloc): Range check
            reloc offset.  Support final-linking.
            (coff_aarch64_po12l_reloc): Likewise.
            (coff_aarch64_addr32nb_reloc): Likewise.
            (coff_aarch64_secrel_reloc): Likewise.
            (coff_pe_aarch64_relocate_section): Range check reloc offset.

Diff:
---
 bfd/coff-aarch64.c | 199 ++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 157 insertions(+), 42 deletions(-)

diff --git a/bfd/coff-aarch64.c b/bfd/coff-aarch64.c
index 7057396f6dd..73fa2442dfe 100644
--- a/bfd/coff-aarch64.c
+++ b/bfd/coff-aarch64.c
@@ -39,48 +39,85 @@
 
 #include "libcoff.h"
 
+/* For these howto special functions,
+   output_bfd == NULL => final link, or objdump -W and other calls to
+   bfd_simple_get_relocated_section_contents
+   output_bfd != NULL && output_bfd != abfd => ld -r
+   output_bfd != NULL && output_bfd == abfd => gas.
+   FIXME: ld -r is punted to bfd_perform_relocation.  This won't be
+   correct for cases where the addend needs to be adjusted, eg. for
+   relocations against section symbols, and the field is split because
+   bfd_perform_relocation can't write addends to split relocation fields.  */
+
 static bfd_reloc_status_type
-coff_aarch64_rel21_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_rel21_reloc (bfd *abfd,
 			  arelent *reloc_entry,
-			  asymbol *symbol ATTRIBUTE_UNUSED,
+			  asymbol *symbol,
 			  void *data,
-			  asection *input_section ATTRIBUTE_UNUSED,
-			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  asection *input_section,
+			  bfd *output_bfd,
 			  char **error_message ATTRIBUTE_UNUSED)
 {
-  uint32_t op;
-  int32_t param;
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
 
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend;
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
 
-  if (param > 0xfffff || param < -0x100000)
-    return bfd_reloc_overflow;
+  uint32_t op = bfd_getl32 (data + reloc_entry->address);
+  bfd_vma relocation = reloc_entry->addend;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset
+		       + symbol->section->output_section->vma);
+      bfd_vma addend = ((op >> 3) & 0x1ffffc) | ((op >> 29) & 0x3);
+      addend = (addend ^ 0x100000) - 0x100000;
+      relocation += addend;
+      relocation -= (reloc_entry->address
+		     + input_section->output_offset
+		     + input_section->output_section->vma);
+      relocation = (bfd_signed_vma) relocation >> reloc_entry->howto->rightshift;
+    }
+  if (relocation + 0x100000 > 0x1fffff)
+    ret = bfd_reloc_overflow;
 
   op &= 0x9f00001f;
-  op |= (param & 0x1ffffc) << 3;
-  op |= (param & 0x3) << 29;
+  op |= (relocation & 0x1ffffc) << 3;
+  op |= (relocation & 0x3) << 29;
 
   bfd_putl32 (op, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 static bfd_reloc_status_type
-coff_aarch64_po12l_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_po12l_reloc (bfd *abfd,
 			  arelent *reloc_entry,
 			  asymbol *symbol ATTRIBUTE_UNUSED,
 			  void *data,
-			  asection *input_section ATTRIBUTE_UNUSED,
-			  bfd *output_bfd ATTRIBUTE_UNUSED,
+			  asection *input_section,
+			  bfd *output_bfd,
 			  char **error_message ATTRIBUTE_UNUSED)
 {
-  uint32_t op;
-  int32_t param;
-  uint8_t shift;
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
 
-  op = bfd_getl32 (data + reloc_entry->address);
-  param = reloc_entry->addend & 0xfff;
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
+
+  uint32_t op = bfd_getl32 (data + reloc_entry->address);
+  bfd_vma relocation = reloc_entry->addend & 0xfff;
+  int shift;
 
   if ((op & 0xff800000) == 0x3d800000)
     {
@@ -93,53 +130,120 @@ coff_aarch64_po12l_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       shift = op >> 30;
     }
 
-  if (param & ((1 << shift) - 1))
-    return bfd_reloc_overflow;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset
+		       + symbol->section->output_section->vma);
+      bfd_vma addend = (op >> 10) & 0xfff;
+      addend <<= shift;
+      relocation += addend;
+    }
 
-  param >>= shift;
+  if (relocation & ((1 << shift) - 1))
+    ret = bfd_reloc_overflow;
 
   op &= 0xffc003ff;
-  op |= param << 10;
+  op |= (relocation >> shift << 10) & 0x3ffc00;
 
   bfd_putl32 (op, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 static bfd_reloc_status_type
-coff_aarch64_addr32nb_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_addr32nb_reloc (bfd *abfd,
 			     arelent *reloc_entry,
 			     asymbol *symbol ATTRIBUTE_UNUSED,
 			     void *data,
-			     asection *input_section ATTRIBUTE_UNUSED,
-			     bfd *output_bfd ATTRIBUTE_UNUSED,
-			     char **error_message ATTRIBUTE_UNUSED)
+			     asection *input_section,
+			     bfd *output_bfd,
+			     char **error_message)
 {
-  uint64_t val;
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
 
-  if ((int64_t) reloc_entry->addend > 0x7fffffff
-      || (int64_t) reloc_entry->addend < -0x7fffffff)
-    return bfd_reloc_overflow;
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
 
-  val = reloc_entry->addend;
+  bfd_vma relocation = reloc_entry->addend;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset
+		       + symbol->section->output_section->vma);
+      bfd_vma addend = bfd_getl_signed_32 (data + reloc_entry->address);
+      relocation += addend;
+      if (bfd_get_flavour (output_bfd) == bfd_target_coff_flavour
+	  && obj_pe (output_bfd))
+	relocation -= pe_data (output_bfd)->pe_opthdr.ImageBase;
+      else
+	{
+	  *error_message = "unsupported";
+	  return bfd_reloc_dangerous;
+	}
+    }
+
+  if (relocation + 0x80000000 > 0xffffffff)
+    ret = bfd_reloc_overflow;
 
-  bfd_putl32 ((uint32_t) val, data + reloc_entry->address);
+  bfd_putl32 (relocation, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 static bfd_reloc_status_type
-coff_aarch64_secrel_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+coff_aarch64_secrel_reloc (bfd *abfd,
 			   arelent *reloc_entry,
 			   asymbol *symbol ATTRIBUTE_UNUSED,
 			   void *data,
-			   asection *input_section ATTRIBUTE_UNUSED,
-			   bfd *output_bfd ATTRIBUTE_UNUSED,
+			   asection *input_section,
+			   bfd *output_bfd,
 			   char **error_message ATTRIBUTE_UNUSED)
 {
-  bfd_putl32 (reloc_entry->addend, data + reloc_entry->address);
+  if (output_bfd != NULL && output_bfd != abfd)
+    return bfd_reloc_continue;
+
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+				  input_section, reloc_entry->address))
+    return bfd_reloc_outofrange;
+
+  bfd_vma relocation = reloc_entry->addend;
+  bfd_reloc_status_type ret = bfd_reloc_ok;
+  if (output_bfd == NULL)
+    {
+      if (bfd_is_und_section (symbol->section))
+	{
+	  if ((symbol->flags & BSF_WEAK) == 0)
+	    ret = bfd_reloc_undefined;
+	}
+      else if (!bfd_is_com_section (symbol->section))
+	relocation += (symbol->value
+		       + symbol->section->output_offset);
+      bfd_vma addend = bfd_getl_signed_32 (data + reloc_entry->address);
+      relocation += addend;
+    }
+  if (relocation > 0xffffffff)
+    ret = bfd_reloc_overflow;
+
+  bfd_putl32 (relocation, data + reloc_entry->address);
 
-  return bfd_reloc_ok;
+  return ret;
 }
 
 #define coff_aarch64_NULL NULL
@@ -438,6 +542,17 @@ coff_pe_aarch64_relocate_section (bfd *output_bfd,
 	  || (unsigned long) symndx >= obj_raw_syment_count (input_bfd))
 	continue;
 
+      /* All the relocs handled below operate on 4 bytes.  */
+      if (input_section->size < rel->r_vaddr
+	  || input_section->size - rel->r_vaddr < 4)
+	{
+	  _bfd_error_handler
+	    /* xgettext: c-format */
+	    (_("%pB: bad reloc address %#" PRIx64 " in section `%pA'"),
+	     input_bfd, (uint64_t) rel->r_vaddr, input_section);
+	  continue;
+	}
+
       switch (rel->r_type)
 	{
 	case IMAGE_REL_ARM64_ADDR32NB:

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-01-19  7:14 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-19  7:14 [binutils-gdb] The fuzzers have found the reloc special functions in coff-aarch64.c Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).