Fix a memory access violation when attempting to parse a corrupt COFF binary with...
authorNick Clifton <nickc@redhat.com>
Tue, 28 Nov 2017 13:20:31 +0000 (13:20 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 28 Nov 2017 13:20:31 +0000 (13:20 +0000)
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.

bfd/ChangeLog
bfd/bfd-in2.h
bfd/coff-arm.c
bfd/coff-i386.c
bfd/coff-i860.c
bfd/coff-m68k.c
bfd/coff-m88k.c
bfd/coff-mips.c
bfd/coff-x86_64.c
bfd/reloc.c

index e2b94abaf0ab7997b71448fa89d15776afffc8c2..13ff8ad242e26c57b8123e774d71de9ec46a8d71 100644 (file)
@@ -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
index 1b483bd863261cb2aba55625b88b588d990a46dc..db1c4807e6ac80e7fcceea7c5eaa62be3fd04a72 100644 (file)
@@ -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,
index 8a2fe1a5fb334f89927b9977b043cfa898f218d1..1e66cbcaf8179f7efc3b03f7f7f253ce90726889 100644 (file)
@@ -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;
index b6ef597af7e7a73ec18e4c975960e96e3bb812e0..91371d850253dc07a6af6fffa5397a270d7acc87 100644 (file)
@@ -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:
index a3c22c653c90f424cb3f7f5eca340b17056da61e..e2e49f9219e6eb5379b4c4cf8ace04cb927de986 100644 (file)
@@ -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:
index dff6e1d99f4656370625961c56164e84aa88c2ff..1730c11eb1e2b86632f13bdcacacadb05144ec5a 100644 (file)
@@ -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:
index ebe4fd3e4f61df83f4d421b36408ee07993763eb..6314bd35f9f22b4d273eec615e3e2f215e178258 100644 (file)
@@ -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.  */
 
index c3ade6216999d6d6ee206530af23e894f76c0f20..ac2b9345196cb8e88dc85beef0eca1848774f7b3 100644 (file)
@@ -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
index de22822e7b2720d5243199b20e755bacd5b05094..4d0bf1835fd31e5941895ed25024fcf7efaa0c9c 100644 (file)
@@ -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)
        {
index 7ee7844d02747c6670782944b27b739e47c917a6..0fe93be118e3a4c138d1228eac35e6859503ce32 100644 (file)
@@ -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