Fix address violation errors parsing corrupt binary files.
authorNick Clifton <nickc@redhat.com>
Mon, 24 Jul 2017 12:49:22 +0000 (13:49 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 24 Jul 2017 12:49:22 +0000 (13:49 +0100)
PR 21813
binutils* rddbg.c (read_symbol_stabs_debugging_info): Check for an empty
string whilst concatenating symbol names.

bfd * 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.

bfd/ChangeLog
bfd/mach-o-aarch64.c
bfd/mach-o-arm.c
bfd/mach-o-i386.c
bfd/mach-o-x86-64.c
bfd/mach-o.c
bfd/mach-o.h
bfd/vms-alpha.c
binutils/ChangeLog
binutils/rddbg.c

index e3da4f5..a854a12 100644 (file)
@@ -1,5 +1,29 @@
 2017-07-24  Nick Clifton  <nickc@redhat.com>
 
 2017-07-24  Nick Clifton  <nickc@redhat.com>
 
+       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.
+
+2017-07-24  Nick Clifton  <nickc@redhat.com>
+
        PR 21803
        * reloc.c (_bfd_unrecognized_reloc): New function.  Reports
        an unrecognized reloc and sets the bfd_error value.
        PR 21803
        * reloc.c (_bfd_unrecognized_reloc): New function.  Reports
        an unrecognized reloc and sets the bfd_error value.
index 12fc47e..5cf3364 100644 (file)
@@ -147,9 +147,11 @@ static reloc_howto_type arm64_howto_table[]=
 };
 
 static bfd_boolean
 };
 
 static bfd_boolean
-bfd_mach_o_arm64_canonicalize_one_reloc (bfd *abfd,
-                                      struct mach_o_reloc_info_external *raw,
-                                        arelent *res, asymbol **syms)
+bfd_mach_o_arm64_canonicalize_one_reloc (bfd *       abfd,
+                                        struct mach_o_reloc_info_external * raw,
+                                        arelent *   res,
+                                        asymbol **  syms,
+                                        arelent *   res_base ATTRIBUTE_UNUSED)
 {
   bfd_mach_o_reloc_info reloc;
 
 {
   bfd_mach_o_reloc_info reloc;
 
index 5139f79..9eb614c 100644 (file)
@@ -30,7 +30,7 @@
 #define bfd_mach_o_mkobject bfd_mach_o_arm_mkobject
 
 #define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_arm_canonicalize_one_reloc
 #define bfd_mach_o_mkobject bfd_mach_o_arm_mkobject
 
 #define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_arm_canonicalize_one_reloc
-#define bfd_mach_o_swap_reloc_out NULL
+#define bfd_mach_o_swap_reloc_out  NULL
 #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm_bfd_reloc_type_lookup
 #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm_bfd_reloc_name_lookup
 
 #define bfd_mach_o_bfd_reloc_type_lookup bfd_mach_o_arm_bfd_reloc_type_lookup
 #define bfd_mach_o_bfd_reloc_name_lookup bfd_mach_o_arm_bfd_reloc_name_lookup
 
@@ -147,9 +147,11 @@ static reloc_howto_type arm_howto_table[]=
 };
 
 static bfd_boolean
 };
 
 static bfd_boolean
-bfd_mach_o_arm_canonicalize_one_reloc (bfd *abfd,
-                                      struct mach_o_reloc_info_external *raw,
-                                      arelent *res, asymbol **syms)
+bfd_mach_o_arm_canonicalize_one_reloc (bfd *       abfd,
+                                      struct mach_o_reloc_info_external * raw,
+                                      arelent *   res,
+                                      asymbol **  syms,
+                                      arelent *   res_base)
 {
   bfd_mach_o_reloc_info reloc;
 
 {
   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:
       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];
           if (reloc.r_length == 2)
             {
              res->howto = &arm_howto_table[7];
index ce0389e..803af98 100644 (file)
@@ -112,9 +112,11 @@ static reloc_howto_type i386_howto_table[]=
 };
 
 static bfd_boolean
 };
 
 static bfd_boolean
-bfd_mach_o_i386_canonicalize_one_reloc (bfd *abfd,
-                                       struct mach_o_reloc_info_external *raw,
-                                       arelent *res, asymbol **syms)
+bfd_mach_o_i386_canonicalize_one_reloc (bfd *       abfd,
+                                       struct mach_o_reloc_info_external * raw,
+                                       arelent *   res,
+                                       asymbol **  syms,
+                                       arelent *   res_base)
 {
   bfd_mach_o_reloc_info reloc;
 
 {
   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:
       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];
           if (reloc.r_length == 2)
             {
              res->howto = &i386_howto_table[7];
@@ -391,9 +396,9 @@ const mach_o_segment_name_xlat mach_o_i386_segsec_names_xlat[] =
     { NULL, NULL }
   };
 
     { NULL, NULL }
   };
 
-#define bfd_mach_o_canonicalize_one_reloc bfd_mach_o_i386_canonicalize_one_reloc
-#define bfd_mach_o_swap_reloc_out bfd_mach_o_i386_swap_reloc_out
-#define bfd_mach_o_print_thread bfd_mach_o_i386_print_thread
+#define bfd_mach_o_canonicalize_one_reloc  bfd_mach_o_i386_canonicalize_one_reloc
+#define bfd_mach_o_swap_reloc_out          bfd_mach_o_i386_swap_reloc_out
+#define bfd_mach_o_print_thread            bfd_mach_o_i386_print_thread
 
 #define bfd_mach_o_tgt_seg_table mach_o_i386_segsec_names_xlat
 #define bfd_mach_o_section_type_valid_for_tgt NULL
 
 #define bfd_mach_o_tgt_seg_table mach_o_i386_segsec_names_xlat
 #define bfd_mach_o_section_type_valid_for_tgt NULL
index 1c83b10..2c50476 100644 (file)
@@ -120,9 +120,11 @@ static reloc_howto_type x86_64_howto_table[]=
 };
 
 static bfd_boolean
 };
 
 static bfd_boolean
-bfd_mach_o_x86_64_canonicalize_one_reloc (bfd *abfd,
-                                       struct mach_o_reloc_info_external *raw,
-                                       arelent *res, asymbol **syms)
+bfd_mach_o_x86_64_canonicalize_one_reloc (bfd *       abfd,
+                                         struct mach_o_reloc_info_external * raw,
+                                         arelent *   res,
+                                         asymbol **  syms,
+                                         arelent *   res_base ATTRIBUTE_UNUSED)
 {
   bfd_mach_o_reloc_info reloc;
 
 {
   bfd_mach_o_reloc_info reloc;
 
index be2fb17..1807391 100644 (file)
@@ -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],
   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);
         goto err;
     }
   free (native_relocs);
index 83660a4..0719b53 100644 (file)
@@ -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)
   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 *);
   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 *);
index 991a1be..5e9170d 100644 (file)
@@ -473,6 +473,14 @@ _bfd_vms_slurp_eihd (bfd *abfd, unsigned int *eisd_offset,
 
   vms_debug2 ((8, "_bfd_vms_slurp_eihd\n"));
 
 
   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);
 
   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;
            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->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);
 
                 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)
              {
 
             if (old_flags & EGSY__V_REL)
              {
+               long psindx;
+
                if (PRIV (sections) == NULL)
                  return FALSE;
                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;
              }
             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 (PRIV (sections) == NULL)
     return;
+  if (sect < 0 || sect >= (int) PRIV (section_count))
+    return;
+
   sec = PRIV (sections)[sect];
 
   if (info)
   sec = PRIV (sections)[sect];
 
   if (info)
@@ -2450,6 +2491,14 @@ _bfd_vms_slurp_eeom (bfd *abfd)
 
   vms_debug2 ((2, "EEOM\n"));
 
 
   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)
   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)
@@ -5173,7 +5222,7 @@ alpha_vms_slurp_relocs (bfd *abfd)
               }
             else if (cur_psidx >= 0)
              {
               }
             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;
                  return FALSE;
                reloc->sym_ptr_ptr =
                  PRIV (sections)[cur_psidx]->symbol_ptr_ptr;
index 0d42604..920e938 100644 (file)
@@ -1,3 +1,9 @@
+2017-07-24  Nick Clifton  <nickc@redhat.com>
+
+       PR 21813
+       * rddbg.c (read_symbol_stabs_debugging_info): Check for an empty
+       string whilst concatenating symbol names.
+
 2017-07-21  Nick Clifton  <nickc@redhat.com>
 
        * po/fr.po: Updated French translation.
 2017-07-21  Nick Clifton  <nickc@redhat.com>
 
        * po/fr.po: Updated French translation.
index 1d8c447..b978060 100644 (file)
@@ -303,7 +303,8 @@ read_symbol_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
            return FALSE;
          f = NULL;
 
            return FALSE;
          f = NULL;
 
-         while (s[strlen (s) - 1] == '\\'
+         while (strlen (s) > 0
+                && s[strlen (s) - 1] == '\\'
                 && ps + 1 < symend)
            {
              char *sc, *n;
                 && ps + 1 < symend)
            {
              char *sc, *n;