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/binutils-2_29-branch] Import patch from mainline to fix address violation errors when parsing corrupt VMS and MACHO binari


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

commit deeb3d27c254ad8bf8c3877fa6b61817f56191f5
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Sep 4 16:31:12 2017 +0100

    Import patch from mainline to fix address violation errors when parsing corrupt VMS and MACHO binaries.
    
    	PR 21813
    	* mach-o.c (bfd_mach_o_canonicalize_relocs): Pass the base address
    	of the relocs to the canonicalize_one_reloc routine.
    	* mach-o.h (struct bfd_mach_o_backend_data): Update the prototype
    	for the _bfd_mach_o_canonicalize_one_reloc field.
    	* mach-o-arm.c (bfd_mach_o_arm_canonicalize_one_reloc): Add
    	res_base parameter.  Use to check for corrupt pair relocs.
    	* mach-o-aarch64.c (bfd_mach_o_arm64_canonicalize_one_reloc):
    	Likewise.
    	* mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc):
    	Likewise.
    	* mach-o-x86-64.c (bfd_mach_o_x86_64_canonicalize_one_reloc):
    	Likewise.
    	* vms-alpha.c (_bfd_vms_slurp_eihd): Make sure that there is
    	enough data in the record before attempting to parse it.
    	(_bfd_vms_slurp_eeom): Likewise.
    	(_bfd_vms_slurp_egsd): Check for an invalid section index.
    	(image_set_ptr): Likewise.
    	(alpha_vms_slurp_relocs): Likewise.
    	(alpha_vms_object_p): Check for a truncated record.

Diff:
---
 bfd/ChangeLog        | 21 ++++++++++++++++++
 bfd/mach-o-aarch64.c |  6 +++--
 bfd/mach-o-arm.c     |  9 ++++++--
 bfd/mach-o-i386.c    |  7 +++++-
 bfd/mach-o-x86-64.c  |  6 +++--
 bfd/mach-o.c         |  2 +-
 bfd/mach-o.h         |  2 +-
 bfd/vms-alpha.c      | 62 +++++++++++++++++++++++++++++++++++++++++++++++-----
 8 files changed, 101 insertions(+), 14 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 7be3d82..ac1e404 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -26,6 +26,27 @@
 	correct magic bytes at the start, set the error to wrong format
 	and clear the format selector before returning NULL.
 
+	PR 21813
+	* mach-o.c (bfd_mach_o_canonicalize_relocs): Pass the base address
+	of the relocs to the canonicalize_one_reloc routine.
+	* mach-o.h (struct bfd_mach_o_backend_data): Update the prototype
+	for the _bfd_mach_o_canonicalize_one_reloc field.
+	* mach-o-arm.c (bfd_mach_o_arm_canonicalize_one_reloc): Add
+	res_base parameter.  Use to check for corrupt pair relocs.
+	* mach-o-aarch64.c (bfd_mach_o_arm64_canonicalize_one_reloc):
+	Likewise.
+	* mach-o-i386.c (bfd_mach_o_i386_canonicalize_one_reloc):
+	Likewise.
+	* mach-o-x86-64.c (bfd_mach_o_x86_64_canonicalize_one_reloc):
+	Likewise.
+	* vms-alpha.c (_bfd_vms_slurp_eihd): Make sure that there is
+	enough data in the record before attempting to parse it.
+	(_bfd_vms_slurp_eeom): Likewise.
+	(_bfd_vms_slurp_egsd): Check for an invalid section index.
+	(image_set_ptr): Likewise.
+	(alpha_vms_slurp_relocs): Likewise.
+	(alpha_vms_object_p): Check for a truncated record.
+
 2017-09-04  Alan Modra  <amodra@gmail.com>
 
 	PR 22067
diff --git a/bfd/mach-o-aarch64.c b/bfd/mach-o-aarch64.c
index 12fc47e..8fc6831 100644
--- a/bfd/mach-o-aarch64.c
+++ b/bfd/mach-o-aarch64.c
@@ -148,8 +148,10 @@ static reloc_howto_type arm64_howto_table[]=
 
 static bfd_boolean
 bfd_mach_o_arm64_canonicalize_one_reloc (bfd *abfd,
-				       struct mach_o_reloc_info_external *raw,
-					 arelent *res, asymbol **syms)
+					 struct mach_o_reloc_info_external *raw,
+					 arelent *res,
+					 asymbol **syms,
+					 arelent *res_base ATTRIBUTE_UNUSED)
 {
   bfd_mach_o_reloc_info reloc;
 
diff --git a/bfd/mach-o-arm.c b/bfd/mach-o-arm.c
index da58679..daeae70 100644
--- a/bfd/mach-o-arm.c
+++ b/bfd/mach-o-arm.c
@@ -148,8 +148,10 @@ static reloc_howto_type arm_howto_table[]=
 
 static bfd_boolean
 bfd_mach_o_arm_canonicalize_one_reloc (bfd *abfd,
-                                      struct mach_o_reloc_info_external *raw,
-                                      arelent *res, asymbol **syms)
+				       struct mach_o_reloc_info_external *raw,
+				       arelent *res,
+				       asymbol **syms,
+				       arelent *res_base)
 {
   bfd_mach_o_reloc_info reloc;
 
@@ -161,6 +163,9 @@ bfd_mach_o_arm_canonicalize_one_reloc (bfd *abfd,
       switch (reloc.r_type)
         {
         case BFD_MACH_O_ARM_RELOC_PAIR:
+	  /* PR 21813: Check for a corrupt PAIR reloc at the start.  */
+	  if (res == res_base)
+	    return FALSE;
           if (reloc.r_length == 2)
             {
 	      res->howto = &arm_howto_table[7];
diff --git a/bfd/mach-o-i386.c b/bfd/mach-o-i386.c
index 82a711e..a2f8380 100644
--- a/bfd/mach-o-i386.c
+++ b/bfd/mach-o-i386.c
@@ -114,7 +114,9 @@ static reloc_howto_type i386_howto_table[]=
 static bfd_boolean
 bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd,
 				        struct mach_o_reloc_info_external *raw,
-					arelent *res, asymbol **syms)
+					arelent *res,
+					asymbol **syms,
+					arelent *res_base)
 {
   bfd_mach_o_reloc_info reloc;
 
@@ -126,6 +128,9 @@ bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd,
       switch (reloc.r_type)
         {
         case BFD_MACH_O_GENERIC_RELOC_PAIR:
+	  /* PR 21813: Check for a corrupt PAIR reloc at the start.  */
+	  if (res == res_base)
+	    return FALSE;
           if (reloc.r_length == 2)
             {
 	      res->howto = &i386_howto_table[7];
diff --git a/bfd/mach-o-x86-64.c b/bfd/mach-o-x86-64.c
index 1c83b10..a374550 100644
--- a/bfd/mach-o-x86-64.c
+++ b/bfd/mach-o-x86-64.c
@@ -121,8 +121,10 @@ static reloc_howto_type x86_64_howto_table[]=
 
 static bfd_boolean
 bfd_mach_o_x86_64_canonicalize_one_reloc (bfd *abfd,
-				        struct mach_o_reloc_info_external *raw,
-					arelent *res, asymbol **syms)
+					  struct mach_o_reloc_info_external *raw,
+					  arelent *res,
+					  asymbol **syms,
+					  arelent *res_base ATTRIBUTE_UNUSED)
 {
   bfd_mach_o_reloc_info reloc;
 
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 51920df..3190774 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -1496,7 +1496,7 @@ bfd_mach_o_canonicalize_relocs (bfd *abfd, unsigned long filepos,
   for (i = 0; i < count; i++)
     {
       if (!(*bed->_bfd_mach_o_canonicalize_one_reloc)(abfd, &native_relocs[i],
-						      &res[i], syms))
+						      &res[i], syms, res))
         goto err;
     }
   free (native_relocs);
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index 83660a4..0719b53 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -746,7 +746,7 @@ typedef struct bfd_mach_o_backend_data
   enum bfd_architecture arch;
   bfd_vma page_size;
   bfd_boolean (*_bfd_mach_o_canonicalize_one_reloc)
-    (bfd *, struct mach_o_reloc_info_external *, arelent *, asymbol **);
+  (bfd *, struct mach_o_reloc_info_external *, arelent *, asymbol **, arelent *);
   bfd_boolean (*_bfd_mach_o_swap_reloc_out)(arelent *, bfd_mach_o_reloc_info *);
   bfd_boolean (*_bfd_mach_o_print_thread)(bfd *, bfd_mach_o_thread_flavour *,
                                           void *, char *);
diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c
index 0b41db4..d8ffa4e 100644
--- a/bfd/vms-alpha.c
+++ b/bfd/vms-alpha.c
@@ -473,6 +473,14 @@ _bfd_vms_slurp_eihd (bfd *abfd, unsigned int *eisd_offset,
 
   vms_debug2 ((8, "_bfd_vms_slurp_eihd\n"));
 
+  /* PR 21813: Check for an undersized record.  */
+  if (PRIV (recrd.buf_size) < sizeof (* eihd))
+    {
+      _bfd_error_handler (_("Corrupt EIHD record - size is too small"));
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
   size = bfd_getl32 (eihd->size);
   imgtype = bfd_getl32 (eihd->imgtype);
 
@@ -1312,19 +1320,38 @@ _bfd_vms_slurp_egsd (bfd *abfd)
 	    if (old_flags & EGSY__V_DEF)
               {
                 struct vms_esdf *esdf = (struct vms_esdf *)vms_rec;
+		long psindx;
 
 		entry->value = bfd_getl64 (esdf->value);
 		if (PRIV (sections) == NULL)
 		  return FALSE;
-		entry->section = PRIV (sections)[bfd_getl32 (esdf->psindx)];
+
+		psindx = bfd_getl32 (esdf->psindx);
+		/* PR 21813: Check for an out of range index.  */
+		if (psindx < 0 || psindx >= (int) PRIV (section_count))
+		  {
+		    _bfd_error_handler (_("Corrupt EGSD record: its psindx field is too big (%#lx)"),
+					psindx);
+		    bfd_set_error (bfd_error_bad_value);
+		    return FALSE;
+		  }
+		entry->section = PRIV (sections)[psindx];
 
                 if (old_flags & EGSY__V_NORM)
                   {
                     PRIV (norm_sym_count)++;
 
                     entry->code_value = bfd_getl64 (esdf->code_address);
-                    entry->code_section =
-                      PRIV (sections)[bfd_getl32 (esdf->ca_psindx)];
+		    psindx = bfd_getl32 (esdf->ca_psindx);
+		    /* PR 21813: Check for an out of range index.  */
+		    if (psindx < 0 || psindx >= (int) PRIV (section_count))
+		      {
+			_bfd_error_handler (_("Corrupt EGSD record: its psindx field is too big (%#lx)"),
+					    psindx);
+			bfd_set_error (bfd_error_bad_value);
+			return FALSE;
+		      }
+                    entry->code_section = PRIV (sections)[psindx];
                   }
               }
 	  }
@@ -1351,9 +1378,20 @@ _bfd_vms_slurp_egsd (bfd *abfd)
 
             if (old_flags & EGSY__V_REL)
 	      {
+		long psindx;
+
 		if (PRIV (sections) == NULL)
 		  return FALSE;
-		entry->section = PRIV (sections)[bfd_getl32 (egst->psindx)];
+		psindx = bfd_getl32 (egst->psindx);
+		/* PR 21813: Check for an out of range index.  */
+		if (psindx < 0 || psindx >= (int) PRIV (section_count))
+		  {
+		    _bfd_error_handler (_("Corrupt EGSD record: its psindx field is too big (%#lx)"),
+					psindx);
+		    bfd_set_error (bfd_error_bad_value);
+		    return FALSE;
+		  }
+		entry->section = PRIV (sections)[psindx];
 	      }
             else
               entry->section = bfd_abs_section_ptr;
@@ -1446,6 +1484,9 @@ image_set_ptr (bfd *abfd, bfd_vma vma, int sect, struct bfd_link_info *info)
 
   if (PRIV (sections) == NULL)
     return;
+  if (sect < 0 || sect >= (int) PRIV (section_count))
+    return;
+
   sec = PRIV (sections)[sect];
 
   if (info)
@@ -2450,6 +2491,14 @@ _bfd_vms_slurp_eeom (bfd *abfd)
 
   vms_debug2 ((2, "EEOM\n"));
 
+  /* PR 21813: Check for an undersized record.  */
+  if (PRIV (recrd.buf_size) < sizeof (* eeom))
+    {
+      _bfd_error_handler (_("Corrupt EEOM record - size is too small"));
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
   PRIV (eom_data).eom_l_total_lps = bfd_getl32 (eeom->total_lps);
   PRIV (eom_data).eom_w_comcod = bfd_getl16 (eeom->comcod);
   if (PRIV (eom_data).eom_w_comcod > 1)
@@ -2630,6 +2679,9 @@ alpha_vms_object_p (bfd *abfd)
           PRIV (recrd.buf_size) = PRIV (recrd.rec_size);
         }
 
+      /* PR 21813: Check for a truncated record.  */
+      if (PRIV (recrd.rec_size < test_len))
+	goto error_ret;
       /* Read the remaining record.  */
       remaining = PRIV (recrd.rec_size) - test_len;
       to_read = MIN (VMS_BLOCK_SIZE - test_len, remaining);
@@ -5173,7 +5225,7 @@ alpha_vms_slurp_relocs (bfd *abfd)
               }
             else if (cur_psidx >= 0)
 	      {
-		if (PRIV (sections) == NULL)
+		if (PRIV (sections) == NULL || cur_psidx >= (int) PRIV (section_count))
 		  return FALSE;
 		reloc->sym_ptr_ptr =
 		  PRIV (sections)[cur_psidx]->symbol_ptr_ptr;


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