This is the mail archive of the binutils-cvs@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]

[binutils-gdb] Fix a memory access violation when attempting to parse a corrupt COFF binary with a relocation that


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

commit b23dc97fe237a1d9e850d7cbeee066183a00630b
Author: Nick Clifton <nickc@redhat.com>
Date:   Tue Nov 28 13:20:31 2017 +0000

    Fix a memory access violation when attempting to parse a corrupt COFF binary with a relocation that points beyond the end of the section to be relocated.
    
    	PR 22506
    	* reloc.c (reloc_offset_in_range): Rename to
    	bfd_reloc_offset_in_range and export.
    	(bfd_perform_relocation): Rename function invocation.
    	(bfd_install_relocation): Likewise.
    	(bfd_final_link_relocate): Likewise.
    	* bfd-in2.h: Regenerate.
    	* coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range.
    	* coff-i386.c (coff_i386_reloc): Likewise.
    	* coff-i860.c (coff_i860_reloc): Likewise.
    	* coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise.
    	* coff-m88k.c (m88k_special_reloc): Likewise.
    	* coff-mips.c (mips_reflo_reloc): Likewise.
    	* coff-x86_64.c (coff_amd64_reloc): Likewise.

Diff:
---
 bfd/ChangeLog     | 17 +++++++++++++++
 bfd/bfd-in2.h     |  6 +++++
 bfd/coff-arm.c    | 65 ++++++++++++++++++++++++++++++-------------------------
 bfd/coff-i386.c   |  5 +++++
 bfd/coff-i860.c   |  5 +++++
 bfd/coff-m68k.c   |  5 +++++
 bfd/coff-m88k.c   |  9 +++++++-
 bfd/coff-mips.c   |  6 +++++
 bfd/coff-x86_64.c | 16 +++++---------
 bfd/reloc.c       | 40 +++++++++++++++++++++++++++++-----
 10 files changed, 126 insertions(+), 48 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index e2b94ab..13ff8ad 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,20 @@
+2017-11-28  Nick Clifton  <nickc@redhat.com>
+
+	PR 22506
+	* reloc.c (reloc_offset_in_range): Rename to
+	bfd_reloc_offset_in_range and export.
+	(bfd_perform_relocation): Rename function invocation.
+	(bfd_install_relocation): Likewise.
+	(bfd_final_link_relocate): Likewise.
+	* bfd-in2.h: Regenerate.
+	* coff-arm.c (coff_arm_reloc): Use bfd_reloc_offset_in_range.
+	* coff-i386.c (coff_i386_reloc): Likewise.
+	* coff-i860.c (coff_i860_reloc): Likewise.
+	* coff-m68k.c (mk68kcoff_common_addend_special_fn): Likewise.
+	* coff-m88k.c (m88k_special_reloc): Likewise.
+	* coff-mips.c (mips_reflo_reloc): Likewise.
+	* coff-x86_64.c (coff_amd64_reloc): Likewise.
+
 2017-11-28  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* elf-m10300.c (mn10300_elf_check_relocs): Don't set
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 1b483bd..db1c480 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2662,6 +2662,12 @@ bfd_reloc_status_type bfd_check_overflow
     unsigned int addrsize,
     bfd_vma relocation);
 
+bfd_boolean bfd_reloc_offset_in_range
+   (reloc_howto_type *howto,
+    bfd *abfd,
+    asection *section,
+    bfd_size_type offset);
+
 bfd_reloc_status_type bfd_perform_relocation
    (bfd *abfd,
     arelent *reloc_entry,
diff --git a/bfd/coff-arm.c b/bfd/coff-arm.c
index 8a2fe1a..1e66cbc 100644
--- a/bfd/coff-arm.c
+++ b/bfd/coff-arm.c
@@ -109,41 +109,46 @@ coff_arm_reloc (bfd *abfd,
   x = ((x & ~howto->dst_mask)					\
        | (((x & howto->src_mask) + diff) & howto->dst_mask))
 
-    if (diff != 0)
-      {
-	reloc_howto_type *howto = reloc_entry->howto;
-	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+  if (diff != 0)
+    {
+      reloc_howto_type *howto = reloc_entry->howto;
+      unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
-	switch (howto->size)
-	  {
-	  case 0:
-	    {
-	      char x = bfd_get_8 (abfd, addr);
-	      DOIT (x);
-	      bfd_put_8 (abfd, x, addr);
-	    }
-	    break;
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+				       reloc_entry->address
+				       * bfd_octets_per_byte (abfd)))
+	return bfd_reloc_outofrange;
 
-	  case 1:
-	    {
-	      short x = bfd_get_16 (abfd, addr);
-	      DOIT (x);
-	      bfd_put_16 (abfd, (bfd_vma) x, addr);
-	    }
-	    break;
+      switch (howto->size)
+	{
+	case 0:
+	  {
+	    char x = bfd_get_8 (abfd, addr);
+	    DOIT (x);
+	    bfd_put_8 (abfd, x, addr);
+	  }
+	  break;
 
-	  case 2:
-	    {
-	      long x = bfd_get_32 (abfd, addr);
-	      DOIT (x);
-	      bfd_put_32 (abfd, (bfd_vma) x, addr);
-	    }
-	    break;
+	case 1:
+	  {
+	    short x = bfd_get_16 (abfd, addr);
+	    DOIT (x);
+	    bfd_put_16 (abfd, (bfd_vma) x, addr);
+	  }
+	  break;
 
-	  default:
-	    abort ();
+	case 2:
+	  {
+	    long x = bfd_get_32 (abfd, addr);
+	    DOIT (x);
+	    bfd_put_32 (abfd, (bfd_vma) x, addr);
 	  }
-      }
+	  break;
+
+	default:
+	  abort ();
+	}
+    }
 
   /* Now let bfd_perform_relocation finish everything up.  */
   return bfd_reloc_continue;
diff --git a/bfd/coff-i386.c b/bfd/coff-i386.c
index b6ef597..91371d8 100644
--- a/bfd/coff-i386.c
+++ b/bfd/coff-i386.c
@@ -144,6 +144,11 @@ coff_i386_reloc (bfd *abfd,
       reloc_howto_type *howto = reloc_entry->howto;
       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+				       reloc_entry->address
+				       * bfd_octets_per_byte (abfd)))
+	return bfd_reloc_outofrange;
+
       switch (howto->size)
 	{
 	case 0:
diff --git a/bfd/coff-i860.c b/bfd/coff-i860.c
index a3c22c6..e2e49f9 100644
--- a/bfd/coff-i860.c
+++ b/bfd/coff-i860.c
@@ -95,6 +95,11 @@ coff_i860_reloc (bfd *abfd,
 	reloc_howto_type *howto = reloc_entry->howto;
 	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+	if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+					 reloc_entry->address
+					 * bfd_octets_per_byte (abfd)))
+	  return bfd_reloc_outofrange;
+
 	switch (howto->size)
 	  {
 	  case 0:
diff --git a/bfd/coff-m68k.c b/bfd/coff-m68k.c
index dff6e1d..1730c11 100644
--- a/bfd/coff-m68k.c
+++ b/bfd/coff-m68k.c
@@ -305,6 +305,11 @@ m68kcoff_common_addend_special_fn (bfd *abfd,
       reloc_howto_type *howto = reloc_entry->howto;
       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+				       reloc_entry->address
+				       * bfd_octets_per_byte (abfd)))
+	return bfd_reloc_outofrange;
+
       switch (howto->size)
 	{
 	case 0:
diff --git a/bfd/coff-m88k.c b/bfd/coff-m88k.c
index ebe4fd3..6314bd3 100644
--- a/bfd/coff-m88k.c
+++ b/bfd/coff-m88k.c
@@ -72,10 +72,17 @@ m88k_special_reloc (bfd *abfd,
 	{
 	  bfd_vma output_base = 0;
 	  bfd_vma addr = reloc_entry->address;
-	  bfd_vma x = bfd_get_16 (abfd, (bfd_byte *) data + addr);
+	  bfd_vma x;
 	  asection *reloc_target_output_section;
 	  long relocation = 0;
 
+	  if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+					   reloc_entry->address
+					   * bfd_octets_per_byte (abfd)))
+	    return bfd_reloc_outofrange;
+
+	  x = bfd_get_16 (abfd, (bfd_byte *) data + addr);	  
+
 	  /* Work out which section the relocation is targeted at and the
 	     initial relocation command value.  */
 
diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c
index c3ade62..ac2b934 100644
--- a/bfd/coff-mips.c
+++ b/bfd/coff-mips.c
@@ -504,6 +504,12 @@ mips_reflo_reloc (bfd *abfd ATTRIBUTE_UNUSED,
 	  unsigned long vallo;
 	  struct mips_hi *next;
 
+	  if (! bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+					   input_section,
+					   reloc_entry->address
+					   * bfd_octets_per_byte (abfd)))
+	    return bfd_reloc_outofrange;
+	  
 	  /* Do the REFHI relocation.  Note that we actually don't
 	     need to know anything about the REFLO itself, except
 	     where to find the low 16 bits of the addend needed by the
diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c
index de22822..4d0bf18 100644
--- a/bfd/coff-x86_64.c
+++ b/bfd/coff-x86_64.c
@@ -142,17 +142,11 @@ coff_amd64_reloc (bfd *abfd,
     {
       reloc_howto_type *howto = reloc_entry->howto;
       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
-
-      /* FIXME: We do not have an end address for data, so we cannot
-	 accurately range check any addresses computed against it.
-	 cf: PR binutils/17512: file: 1085-1761-0.004.
-	 For now we do the best that we can.  */
-      if (addr < (unsigned char *) data
-	  || addr > ((unsigned char *) data) + input_section->size)
-	{
-	  bfd_set_error (bfd_error_bad_value);
-	  return bfd_reloc_notsupported;
-	}
+      
+      if (! bfd_reloc_offset_in_range (howto, abfd, input_section,
+				       reloc_entry->address
+				       * bfd_octets_per_byte (abfd)))
+	return bfd_reloc_outofrange;
 
       switch (howto->size)
 	{
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 7ee7844..0fe93be 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -540,12 +540,31 @@ bfd_check_overflow (enum complain_overflow how,
   return flag;
 }
 
+/*
+FUNCTION
+	bfd_reloc_offset_in_range
+
+SYNOPSIS
+	bfd_boolean bfd_reloc_offset_in_range
+          (reloc_howto_type *howto,
+           bfd *abfd,
+           asection *section,
+           bfd_size_type offset);
+
+DESCRIPTION
+        Returns TRUE if the reloc described by @var{HOWTO} can be
+	applied at @var{OFFSET} octets in @var{SECTION}.
+
+*/
+
 /* HOWTO describes a relocation, at offset OCTET.  Return whether the
    relocation field is within SECTION of ABFD.  */
 
-static bfd_boolean
-reloc_offset_in_range (reloc_howto_type *howto, bfd *abfd,
-		       asection *section, bfd_size_type octet)
+bfd_boolean
+bfd_reloc_offset_in_range (reloc_howto_type *howto,
+			   bfd *abfd,
+			   asection *section,
+			   bfd_size_type octet)
 {
   bfd_size_type octet_end = bfd_get_section_limit_octets (abfd, section);
   bfd_size_type reloc_size = bfd_get_reloc_size (howto);
@@ -619,6 +638,11 @@ bfd_perform_relocation (bfd *abfd,
   if (howto && howto->special_function)
     {
       bfd_reloc_status_type cont;
+
+      /* Note - we do not call bfd_reloc_offset_in_range here as the
+	 reloc_entry->address field might actually be valid for the
+	 backend concerned.  It is up to the special_function itself
+	 to call bfd_reloc_offset_in_range if needed.  */
       cont = howto->special_function (abfd, reloc_entry, symbol, data,
 				      input_section, output_bfd,
 				      error_message);
@@ -639,7 +663,7 @@ bfd_perform_relocation (bfd *abfd,
 
   /* Is the address of the relocation really within the section?  */
   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
-  if (!reloc_offset_in_range (howto, abfd, input_section, octets))
+  if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
     return bfd_reloc_outofrange;
 
   /* Work out which section the relocation is targeted at and the
@@ -1005,6 +1029,10 @@ bfd_install_relocation (bfd *abfd,
     {
       bfd_reloc_status_type cont;
 
+      /* Note - we do not call bfd_reloc_offset_in_range here as the
+	 reloc_entry->address field might actually be valid for the
+	 backend concerned.  It is up to the special_function itself
+	 to call bfd_reloc_offset_in_range if needed.  */
       /* XXX - The special_function calls haven't been fixed up to deal
 	 with creating new relocations and section contents.  */
       cont = howto->special_function (abfd, reloc_entry, symbol,
@@ -1027,7 +1055,7 @@ bfd_install_relocation (bfd *abfd,
 
   /* Is the address of the relocation really within the section?  */
   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
-  if (!reloc_offset_in_range (howto, abfd, input_section, octets))
+  if (!bfd_reloc_offset_in_range (howto, abfd, input_section, octets))
     return bfd_reloc_outofrange;
 
   /* Work out which section the relocation is targeted at and the
@@ -1365,7 +1393,7 @@ _bfd_final_link_relocate (reloc_howto_type *howto,
   bfd_size_type octets = address * bfd_octets_per_byte (input_bfd);
 
   /* Sanity check the address.  */
-  if (!reloc_offset_in_range (howto, input_bfd, input_section, octets))
+  if (!bfd_reloc_offset_in_range (howto, input_bfd, input_section, octets))
     return bfd_reloc_outofrange;
 
   /* This function assumes that we are dealing with a basic relocation


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