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] Fix undefined arithmetic operations detected by -fsanitize=undefined when running readelf on fuzzed


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

commit c8071705c69a13d237aeca4709bf91deaff7e5cb
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Feb 26 14:21:54 2015 +0000

    Fix undefined arithmetic operations detected by -fsanitize=undefined when running readelf on fuzzed binaries.
    
    	PR binutils/17512
    	* dwarf.c (display_debug_loc): Pacify the undefined behaviour
    	sanitizer by simplifying address difference calculation.
    	(struct Frame_Chunk): Change type of cfa_offset to dwarf_vma in
    	order to avoid arithmetic overflows.
    	(frame_display_row): Cast cfa_offset before printing it.
    	(display_debug_frames): Likewise.
    	Check for an unexpected segment size.
    	Chnage type of 'l' local to dwarf_vma and cast it back to an int
    	when printing.
    	(process_cu_tu_index): Tighten check for an invalid ncols value.
    	* readelf.c (process_corefile_note_segment): Check for
    	inote.descdata extending beyond the end of the section.
    	(process_v850_notes): Likewise.

Diff:
---
 binutils/ChangeLog | 14 ++++++++++++++
 binutils/dwarf.c   | 38 +++++++++++++++++++++++---------------
 binutils/readelf.c | 24 ++++++++++++++++++------
 3 files changed, 55 insertions(+), 21 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 8657b1d..3a42b72 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -4,6 +4,20 @@
 	* resrc.c (write_rc_messagetable): Tighten check for invalid
 	message lengths.
 
+	* dwarf.c (display_debug_loc): Pacify the undefined behaviour
+	sanitizer by simplifying address difference calculation.
+	(struct Frame_Chunk): Change type of cfa_offset to dwarf_vma in
+	order to avoid arithmetic overflows.
+	(frame_display_row): Cast cfa_offset before printing it.
+	(display_debug_frames): Likewise.
+	Check for an unexpected segment size.
+	Chnage type of 'l' local to dwarf_vma and cast it back to an int
+	when printing.
+	(process_cu_tu_index): Tighten check for an invalid ncols value.
+	* readelf.c (process_corefile_note_segment): Check for
+	inote.descdata extending beyond the end of the section.
+	(process_v850_notes): Likewise.
+
 2015-02-26  Terry Guo  <terry.guo@arm.com>
 
 	* readelf.c (arm_attr_tag_ABI_HardFP_use): Update how we
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 272b41f..5884140 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -4719,11 +4719,11 @@ display_debug_loc (struct dwarf_section *section, void *file)
 	      if (start < next)
 		warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
 		      (unsigned long) (start - section_begin),
-		      (unsigned long) (next - section_begin));
+		      (unsigned long) offset);
 	      else if (start > next)
 		warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
 		      (unsigned long) (start - section_begin),
-		      (unsigned long) (next - section_begin));
+		      (unsigned long) offset);
 	    }
 	  start = next;
 
@@ -5244,7 +5244,7 @@ typedef struct Frame_Chunk
   dwarf_vma pc_begin;
   dwarf_vma pc_range;
   int cfa_reg;
-  int cfa_offset;
+  dwarf_vma cfa_offset;
   unsigned int ra;
   unsigned char fde_encoding;
   unsigned char cfa_exp;
@@ -5481,7 +5481,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg
   if (fc->cfa_exp)
     strcpy (tmp, "exp");
   else
-    sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), fc->cfa_offset);
+    sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), (int) fc->cfa_offset);
   printf ("%-8s ", tmp);
 
   for (r = 0; r < fc->ncols; r++)
@@ -5921,7 +5921,15 @@ display_debug_frames (struct dwarf_section *section,
 
 	  segment_selector = 0;
 	  if (fc->segment_size)
-	    SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end);
+	    {
+	      if (fc->segment_size > sizeof (segment_selector))
+		{
+		  /* PR 17512: file: 9e196b3e.  */
+		  warn (_("Probably corrupt segment size: %d - using 4 instead\n"), fc->segment_size);
+		  fc->segment_size = 4;
+		}
+	      SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end);
+	    }
 
 	  fc->pc_begin = get_encoded_value (&start, fc->fde_encoding, section, end);
 
@@ -6123,7 +6131,7 @@ display_debug_frames (struct dwarf_section *section,
 	  unsigned char * tmp;
 	  unsigned op, opa;
 	  unsigned long ul, reg, roffs;
-	  long l;
+	  dwarf_vma l;
 	  dwarf_vma ofs;
 	  dwarf_vma vma;
 	  const char *reg_prefix = "";
@@ -6375,7 +6383,7 @@ display_debug_frames (struct dwarf_section *section,
 	      fc->cfa_exp = 0;
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_def_cfa: %s ofs %d\n",
-			regname (fc->cfa_reg, 0), fc->cfa_offset);
+			regname (fc->cfa_reg, 0), (int) fc->cfa_offset);
 	      break;
 
 	    case DW_CFA_def_cfa_register:
@@ -6389,7 +6397,7 @@ display_debug_frames (struct dwarf_section *section,
 	    case DW_CFA_def_cfa_offset:
 	      fc->cfa_offset = LEB ();
 	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset);
+		printf ("  DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset);
 	      break;
 
 	    case DW_CFA_nop:
@@ -6473,7 +6481,7 @@ display_debug_frames (struct dwarf_section *section,
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
 		printf ("  DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n",
 			reg_prefix, regname (reg, 0),
-			l * fc->data_factor);
+			(long)(l * fc->data_factor));
 	      if (*reg_prefix == '\0')
 		{
 		  fc->col_type[reg] = DW_CFA_offset;
@@ -6489,7 +6497,7 @@ display_debug_frames (struct dwarf_section *section,
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
 		printf ("  DW_CFA_val_offset_sf: %s%s at cfa%+ld\n",
 			reg_prefix, regname (reg, 0),
-			l * fc->data_factor);
+			(long)(l * fc->data_factor));
 	      if (*reg_prefix == '\0')
 		{
 		  fc->col_type[reg] = DW_CFA_val_offset;
@@ -6504,14 +6512,14 @@ display_debug_frames (struct dwarf_section *section,
 	      fc->cfa_exp = 0;
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_def_cfa_sf: %s ofs %d\n",
-			regname (fc->cfa_reg, 0), fc->cfa_offset);
+			regname (fc->cfa_reg, 0), (int) fc->cfa_offset);
 	      break;
 
 	    case DW_CFA_def_cfa_offset_sf:
 	      fc->cfa_offset = SLEB ();
-	      fc->cfa_offset = fc->cfa_offset * fc->data_factor;
+	      fc->cfa_offset *= fc->data_factor;
 	      if (! do_debug_frames_interp)
-		printf ("  DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset);
+		printf ("  DW_CFA_def_cfa_offset_sf: %d\n", (int) fc->cfa_offset);
 	      break;
 
 	    case DW_CFA_MIPS_advance_loc8:
@@ -6546,7 +6554,7 @@ display_debug_frames (struct dwarf_section *section,
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
 		printf ("  DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n",
 			reg_prefix, regname (reg, 0),
-			l * fc->data_factor);
+			(long)(l * fc->data_factor));
 	      if (*reg_prefix == '\0')
 		{
 		  fc->col_type[reg] = DW_CFA_offset;
@@ -7026,7 +7034,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
       /* PR 17531: file: 0dd159bf.
 	 Check for wraparound with an overlarge ncols value.  */
-      if ((unsigned int) ((poffsets - ppool) / 4) != ncols)
+      if (poffsets < ppool || (unsigned int) ((poffsets - ppool) / 4) != ncols)
 	{
 	  warn (_("Overlarge number of columns: %x\n"), ncols);
 	  return 0;
diff --git a/binutils/readelf.c b/binutils/readelf.c
index da616b3..06fa8d5 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -15205,6 +15205,7 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
 {
   Elf_External_Note * pnotes;
   Elf_External_Note * external;
+  char * end;
   int res = 1;
 
   if (length <= 0)
@@ -15221,13 +15222,14 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
 	  (unsigned long) offset, (unsigned long) length);
   printf (_("  %-20s %10s\tDescription\n"), _("Owner"), _("Data size"));
 
-  while ((char *) external < (char *) pnotes + length)
+  end = (char *) pnotes + length;
+  while ((char *) external < end)
     {
       Elf_Internal_Note inote;
       size_t min_notesz;
       char *next;
       char * temp = NULL;
-      size_t data_remaining = ((char *) pnotes + length) - (char *) external;
+      size_t data_remaining = end - (char *) external;
 
       if (!is_ia64_vms ())
 	{
@@ -15246,12 +15248,13 @@ process_corefile_note_segment (FILE * file, bfd_vma offset, bfd_vma length)
 	  inote.descsz   = BYTE_GET (external->descsz);
 	  inote.descdata = inote.namedata + align_power (inote.namesz, 2);
 	  /* PR 17531: file: 3443835e.  */
-	  if (inote.descdata < (char *) pnotes)
+	  if (inote.descdata < (char *) pnotes || inote.descdata > end)
 	    {
 	      warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz);
 	      inote.descdata = inote.namedata;
 	      inote.namesz   = 0;
 	    }
+ 
 	  inote.descpos  = offset + (inote.descdata - (char *) pnotes);
 	  next = inote.descdata + align_power (inote.descsz, 2);
 	}
@@ -15358,6 +15361,7 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length)
 {
   Elf_External_Note * pnotes;
   Elf_External_Note * external;
+  char * end;
   int res = 1;
 
   if (length <= 0)
@@ -15369,11 +15373,12 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length)
     return 0;
 
   external = pnotes;
+  end = (char*) pnotes + length;
 
   printf (_("\nDisplaying contents of Renesas V850 notes section at offset 0x%lx with length 0x%lx:\n"),
 	  (unsigned long) offset, (unsigned long) length);
 
-  while (external < (Elf_External_Note *) ((char *) pnotes + length))
+  while ((char *) external + sizeof (Elf_External_Note) < end)
     {
       Elf_External_Note * next;
       Elf_Internal_Note inote;
@@ -15385,9 +15390,16 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length)
       inote.descdata = inote.namedata + align_power (inote.namesz, 2);
       inote.descpos  = offset + (inote.descdata - (char *) pnotes);
 
+      if (inote.descdata < (char *) pnotes || inote.descdata >= end)
+	{
+	  warn (_("Corrupt note: name size is too big: %lx\n"), inote.namesz);
+	  inote.descdata = inote.namedata;
+	  inote.namesz   = 0;
+	}
+
       next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2));
 
-      if (   ((char *) next > ((char *) pnotes) + length)
+      if (   ((char *) next > end)
 	  || ((char *) next <  (char *) pnotes))
 	{
 	  warn (_("corrupt descsz found in note at offset 0x%lx\n"),
@@ -15400,7 +15412,7 @@ process_v850_notes (FILE * file, bfd_vma offset, bfd_vma length)
       external = next;
 
       /* Prevent out-of-bounds indexing.  */
-      if (   inote.namedata + inote.namesz > (char *) pnotes + length
+      if (   inote.namedata + inote.namesz > end
 	  || inote.namedata + inote.namesz < inote.namedata)
         {
           warn (_("corrupt namesz found in note at offset 0x%lx\n"),


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