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] Prevent memory access violations when attempting to parse an x86_64 PE binary containing corrupt unw


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

commit 3e33b239450771394fa6c83b67b9de80169f35e8
Author: Nick Clifton <nickc@redhat.com>
Date:   Tue Mar 13 14:02:52 2018 +0000

    Prevent memory access violations when attempting to parse an x86_64 PE binary containing corrupt unwind information.
    
    	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.

Diff:
---
 bfd/ChangeLog     | 13 +++++++++++++
 bfd/pei-x86_64.c  | 54 ++++++++++++++++++++++++++++++++++++++++++++++--------
 include/ChangeLog |  6 ++++++
 include/coff/pe.h |  1 +
 4 files changed, 66 insertions(+), 8 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 672143b..ddf0d04 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c
index db30726..3a0248d 100644
--- a/bfd/pei-x86_64.c
+++ b/bfd/pei-x86_64.c
@@ -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)
     {
diff --git a/include/ChangeLog b/include/ChangeLog
index 529f43c..942c02b 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -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.
diff --git a/include/coff/pe.h b/include/coff/pe.h
index 56cc4e2..cb9075a 100644
--- a/include/coff/pe.h
+++ b/include/coff/pe.h
@@ -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.  */


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