Fix access violation when disassembling a corrupt VMS binary.
authorNick Clifton <nickc@redhat.com>
Mon, 19 Jun 2017 11:31:07 +0000 (12:31 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 19 Jun 2017 11:31:07 +0000 (12:31 +0100)
PR 21615
* vms-alpha.c (_bfd_vms_slurp_egsd): Use unsigned int for
gsd_size.  Check that there are enough bytes remaining to read the
type and size of the next egsd.  Check that the size of the egsd
does not exceed the size of the record.

bfd/ChangeLog
bfd/vms-alpha.c

index 9fd767b8f02d02db80d4e4a33a0307f9099fac8f..a900e1ac1650451ebeca78f0fa77e34a8cbecb22 100644 (file)
@@ -1,3 +1,11 @@
+2017-06-19  Nick Clifton  <nickc@redhat.com>
+
+       PR 21615
+       * vms-alpha.c (_bfd_vms_slurp_egsd): Use unsigned int for
+       gsd_size.  Check that there are enough bytes remaining to read the
+       type and size of the next egsd.  Check that the size of the egsd
+       does not exceed the size of the record.
+
 2017-06-19  Alan Modra  <amodra@gmail.com>
 
        * config.bfd: Correct targ_underscore for cris.
index 83b6638cd7000140298103fd628e414a5f433687..be5c06f648fcb3c2ad6099a3ec07efcc42da842d 100644 (file)
@@ -1121,7 +1121,8 @@ add_symbol (bfd *abfd, const unsigned char *ascic)
 static bfd_boolean
 _bfd_vms_slurp_egsd (bfd *abfd)
 {
-  int gsd_type, gsd_size;
+  int gsd_type;
+  unsigned int gsd_size;
   unsigned char *vms_rec;
   unsigned long base_addr;
 
@@ -1133,7 +1134,7 @@ _bfd_vms_slurp_egsd (bfd *abfd)
   /* Calculate base address for each section.  */
   base_addr = 0L;
 
-  while (PRIV (recrd.rec_size) > 0)
+  while (PRIV (recrd.rec_size) > 4)
     {
       vms_rec = PRIV (recrd.rec);
 
@@ -1142,6 +1143,15 @@ _bfd_vms_slurp_egsd (bfd *abfd)
 
       vms_debug2 ((3, "egsd_type %d\n", gsd_type));
 
+      /* PR 21615: Check for size overflow.  */
+      if (PRIV (recrd.rec_size) < gsd_size)
+       {
+         _bfd_error_handler (_("Corrupt EGSD record: size (%#x) is larger than remaining space (%#x)"),
+                             gsd_size, PRIV (recrd.rec_size));
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+
       switch (gsd_type)
        {
        case EGSD__C_PSC: