public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Alan Modra <amodra@gmail.com>
To: binutils@sourceware.org
Cc: Mark Harmstone <mark@harmstone.com>
Subject: [PATCH 4/4] The fuzzers have found the reloc special functions in coff-aarch64.c
Date: Wed, 18 Jan 2023 16:56:57 +1030	[thread overview]
Message-ID: <20230118062657.1125934-5-amodra@gmail.com> (raw)
In-Reply-To: <20230118062657.1125934-1-amodra@gmail.com>

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 --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:

      parent reply	other threads:[~2023-01-18  6:27 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-18  6:26 [PATCH 0/4] bfd_install_relocation and aarch64-pe changes Alan Modra
2023-01-18  6:26 ` [PATCH 1/4] howto install_addend Alan Modra
2023-01-18  6:26 ` [PATCH 2/4] coff-aarch64.c howtos Alan Modra
2023-01-18  6:26 ` [PATCH 3/4] Correct coff-aarch64 howtos and delete unnecessary special functions Alan Modra
2023-01-18  6:26 ` Alan Modra [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230118062657.1125934-5-amodra@gmail.com \
    --to=amodra@gmail.com \
    --cc=binutils@sourceware.org \
    --cc=mark@harmstone.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).