Prevent memory access violations when attempting to parse an x86_64 PE binary contain...
authorNick Clifton <nickc@redhat.com>
Tue, 13 Mar 2018 14:02:52 +0000 (14:02 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 13 Mar 2018 14:02:52 +0000 (14:02 +0000)
PR 22113
incldue * coff/pe.h (struct pex64_unwind_info): Add a rawUnwindCodesEnd
field.

bfd * pei-x86_64.c (pex64_get_unwind_info): Change to a boolean
function.  Add an end address parameter.  Check access of the data
pointer to make sure that they do not extend beyond the end
address.  Return FALSE if any check fails.  Add the end address
pointer to the ui structure.
(pex64_xdata_print_uwd_codes): Check accesses of the raw unwind
codes to make sure that they do not extend beyond the end address
pointer.  Print an error message and return immediately if any
check fails.

bfd/ChangeLog
bfd/pei-x86_64.c
include/ChangeLog
include/coff/pe.h

index 672143b3ffecf4540607c425b02d74f22d9e6fe0..ddf0d041fcdbf903b8f32572ba621067d3fc5a6f 100644 (file)
@@ -1,3 +1,16 @@
+2018-03-13  Nick Clifton  <nickc@redhat.com>
+
+       PR 22113
+       * pei-x86_64.c (pex64_get_unwind_info): Change to a boolean
+       function.  Add an end address parameter.  Check access of the data
+       pointer to make sure that they do not extend beyond the end
+       address.  Return FALSE if any check fails.  Add the end address
+       pointer to the ui structure.
+       (pex64_xdata_print_uwd_codes): Check accesses of the raw unwind
+       codes to make sure that they do not extend beyond the end address
+       pointer.  Print an error message and return immediately if any
+       check fails.
+
 2018-03-09  Nick Clifton  <nickc@redhat.com>
 
        * elf64-s390.c (elf_s390_relocate_section): Move check for
index db307266c83b99cb777a010e72d7c1ddd5d3016a..3a0248de2165079d819540a0da8add428325f08a 100644 (file)
@@ -98,14 +98,20 @@ pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
 
 /* Swap in unwind info header.  */
 
-static void
-pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
+static bfd_boolean
+pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui,
+                      void *data, void *data_end)
 {
   struct external_pex64_unwind_info *ex_ui =
     (struct external_pex64_unwind_info *) data;
   bfd_byte *ex_dta = (bfd_byte *) data;
+  bfd_byte *ex_dta_end = (bfd_byte *) data_end;
 
   memset (ui, 0, sizeof (struct pex64_unwind_info));
+
+  if (ex_dta >= ex_dta_end || ex_dta + 4 >= ex_dta_end)
+    return FALSE;
+
   ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags);
   ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags);
   ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue;
@@ -114,25 +120,33 @@ pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
   ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset);
   ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes);
   ui->SizeOfBlock = ui->sizeofUnwindCodes + 4;
-  ui->rawUnwindCodes = &ex_dta[4];
+  ui->rawUnwindCodes = ex_dta + 4;
+  ui->rawUnwindCodesEnd = ex_dta_end;
 
   ex_dta += ui->SizeOfBlock;
+  if (ex_dta >= ex_dta_end)
+    return FALSE;
+  
   switch (ui->Flags)
     {
     case UNW_FLAG_CHAININFO:
+      if (ex_dta + 12 >= ex_dta_end)
+       return FALSE;
       ui->rva_BeginAddress = bfd_get_32 (abfd, ex_dta + 0);
       ui->rva_EndAddress = bfd_get_32 (abfd, ex_dta + 4);
       ui->rva_UnwindData = bfd_get_32 (abfd, ex_dta + 8);
       ui->SizeOfBlock += 12;
-      return;
+      return TRUE;
     case UNW_FLAG_EHANDLER:
     case UNW_FLAG_UHANDLER:
     case UNW_FLAG_FHANDLER:
+      if (ex_dta + 4 >= ex_dta_end)
+       return FALSE;
       ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta);
       ui->SizeOfBlock += 4;
-      return;
+      return TRUE;
     default:
-      return;
+      return TRUE;
     }
 }
 
@@ -158,6 +172,12 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
 
   i = 0;
 
+  if (ui->rawUnwindCodes + 1 >= ui->rawUnwindCodesEnd)
+    {
+      fprintf (file, _("warning: corrupt unwind data\n"));
+      return;
+    }
+
   if (ui->Version == 2
       && PEX64_UNWCODE_CODE (ui->rawUnwindCodes[1]) == UWOP_EPILOG)
     {
@@ -166,10 +186,18 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
         to decode instruction flow if outside an epilog.  */
       unsigned int func_size = rf->rva_EndAddress - rf->rva_BeginAddress;
 
+      if (ui->rawUnwindCodes + 1 + (ui->CountOfCodes * 2) >= ui->rawUnwindCodesEnd)
+       {
+         fprintf (file, _("warning: corrupt unwind data\n"));
+         return;
+       }
+         
       fprintf (file, "\tv2 epilog (length: %02x) at pc+:",
               ui->rawUnwindCodes[0]);
+
       if (PEX64_UNWCODE_INFO (ui->rawUnwindCodes[1]))
        fprintf (file, " 0x%x", func_size - ui->rawUnwindCodes[0]);
+
       i++;
       for (; i < ui->CountOfCodes; i++)
        {
@@ -187,6 +215,12 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
       fputc ('\n', file);
     }
 
+  if (ui->rawUnwindCodes + 2 + (ui->CountOfCodes * 2) >= ui->rawUnwindCodesEnd)
+    {
+      fprintf (file, _("warning: corrupt unwind data\n"));
+      return;
+    }
+         
   for (; i < ui->CountOfCodes; i++)
     {
       const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
@@ -338,14 +372,18 @@ pex64_dump_xdata (FILE *file, bfd *abfd,
       /* PR 17512: file: 2245-7442-0.004.  */
       if (end_addr > sec_size)
        {
-         fprintf (file, _("warning: xdata section corrupt"));
+         fprintf (file, _("warning: xdata section corrupt\n"));
          end_addr = sec_size;
        }
     }
   else
     end_addr = sec_size;
 
-  pex64_get_unwind_info (abfd, &ui, &xdata[addr]);
+  if (! pex64_get_unwind_info (abfd, &ui, xdata + addr, xdata + end_addr))
+    {
+      fprintf (file, _("warning: xdata section corrupt\n"));
+      return;
+    }
 
   if (ui.Version != 1 && ui.Version != 2)
     {
index 529f43cf7de2c55b5ce33eb66b8b7041d9437bad..942c02be4bbb968c70e267815cef392c0d8b87de 100644 (file)
@@ -1,3 +1,9 @@
+2018-03-13  Nick Clifton  <nickc@redhat.com>
+
+       PR 22113
+       * coff/pe.h (struct pex64_unwind_info): Add a rawUnwindCodesEnd
+       field.
+
 2018-03-08  H.J. Lu  <hongjiu.lu@intel.com>
 
        * opcode/i386 (OLDGCC_COMPAT): Removed.
index 56cc4e20c2c4461cd0216896e54f53f42be97381..cb9075ac6c4f6769763ea0230b4f3b9a1455bcb3 100644 (file)
@@ -497,6 +497,7 @@ struct pex64_unwind_info
   bfd_vma FrameOffset;
   bfd_vma sizeofUnwindCodes;
   bfd_byte *rawUnwindCodes;
+  bfd_byte *rawUnwindCodesEnd;
   bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER or UNW_FLAG_UHANDLER.  */
   bfd_vma rva_BeginAddress;    /* UNW_FLAG_CHAININFO.  */
   bfd_vma rva_EndAddress;      /* UNW_FLAG_CHAININFO.  */