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 address violation when reading corrupt DWARF data.


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

commit 7f2c8a1d37af46c46828909b7b748c79aa4b7ff0
Author: Nick Clifton <nickc@redhat.com>
Date:   Wed Jun 21 18:05:44 2017 +0100

    Fix address violation when reading corrupt DWARF data.
    
    	PR binutils/21648
    	* dwarf.c (LEB): Rename to SKIP_ULEB and READ_ULEB.  Add check for
    	reading a value that is too big for the containing variable.
    	(SLEB): Rename to SKIP_SLEB and READ_SLEB.  Add similar check.
    	Replace uses of LEB and SLEB with appropriate new macro.
    	(display_debug_frames): Use an unsigned int for the 'reg'
    	variable.  Use a signed long for the 'l' variable.

Diff:
---
 binutils/ChangeLog |  10 ++++
 binutils/dwarf.c   | 154 +++++++++++++++++++++++++++++++++--------------------
 2 files changed, 106 insertions(+), 58 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 6997db9..f5da75d 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,13 @@
+2017-06-21  Nick Clifton  <nickc@redhat.com>
+
+	PR binutils/21648
+	* dwarf.c (LEB): Rename to SKIP_ULEB and READ_ULEB.  Add check for
+	reading a value that is too big for the containing variable.
+	(SLEB): Rename to SKIP_SLEB and READ_SLEB.  Add similar check.
+	Replace uses of LEB and SLEB with appropriate new macro.
+	(display_debug_frames): Use an unsigned int for the 'reg'
+	variable.  Use a signed long for the 'l' variable.
+
 2017-06-19  Nick Clifton  <nickc@redhat.com>
 
 	PR binutils/21619
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index cdedbb2..ee46439 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -313,6 +313,35 @@ read_uleb128 (unsigned char * data,
   return read_leb128 (data, length_return, FALSE, end);
 }
 
+#define SKIP_ULEB()	read_uleb128 (start, & length_return, end); start += length_return
+#define SKIP_SLEB()	read_sleb128 (start, & length_return, end); start += length_return
+
+#define READ_ULEB(var)						\
+  do								\
+    {								\
+      dwarf_vma _val;						\
+								\
+      (var) = _val = read_uleb128 (start, &length_return, end);	\
+      if ((var) != _val)					\
+	error (_("Internal error: %s%d: LEB value (%#lx) too large for containing variable\n"),	\
+	       __FILE__, __LINE__, _val);			\
+      start += length_return;					\
+    }								\
+  while (0)
+
+#define READ_SLEB(var)						\
+  do								\
+    {								\
+      dwarf_signed_vma _val;					\
+								\
+      (var) = _val = read_sleb128 (start, &length_return, end);	\
+      if ((var) != _val)					\
+	error (_("Internal error: %s%d: LEB value (%#lx) too large for containing variable\n"),	\
+	       __FILE__, __LINE__, _val);			\
+      start += length_return;					\
+    }								\
+  while (0)
+
 #define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END)	\
   do						\
     {						\
@@ -6421,6 +6450,7 @@ static const char *
 regname (unsigned int regno, int row)
 {
   static char reg[64];
+
   if (dwarf_regnames
       && regno < dwarf_regnames_count
       && dwarf_regnames [regno] != NULL)
@@ -6509,8 +6539,6 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg
 }
 
 #define GET(VAR, N)	SAFE_BYTE_GET_AND_INC (VAR, start, N, end)
-#define LEB()	read_uleb128 (start, & length_return, end); start += length_return
-#define SLEB()	read_sleb128 (start, & length_return, end); start += length_return
 
 static unsigned char *
 read_cie (unsigned char *start, unsigned char *end,
@@ -6575,26 +6603,27 @@ read_cie (unsigned char *start, unsigned char *end,
       fc->ptr_size = eh_addr_size;
       fc->segment_size = 0;
     }
-  fc->code_factor = LEB ();
-  fc->data_factor = SLEB ();
+  READ_ULEB (fc->code_factor);
+  READ_SLEB (fc->data_factor);
   if (version == 1)
     {
       GET (fc->ra, 1);
     }
   else
     {
-      fc->ra = LEB ();
+      READ_ULEB (fc->ra);
     }
 
   if (fc->augmentation[0] == 'z')
     {
-      augmentation_data_len = LEB ();
+      READ_ULEB (augmentation_data_len);
       augmentation_data = start;
       start += augmentation_data_len;
       /* PR 17512: file: 11042-2589-0.004.  */
       if (start > end)
 	{
-	  warn (_("Augmentation data too long: 0x%lx\n"), augmentation_data_len);
+	  warn (_("Augmentation data too long: %#lx, expected at most %#lx\n"),
+		augmentation_data_len, (long)((end - start) + augmentation_data_len));
 	  return end;
 	}
     }
@@ -6929,7 +6958,7 @@ display_debug_frames (struct dwarf_section *section,
 
 	  if (cie->augmentation[0] == 'z')
 	    {
-	      augmentation_data_len = LEB ();
+	      READ_ULEB (augmentation_data_len);
 	      augmentation_data = start;
 	      start += augmentation_data_len;
 	      /* PR 17512: file: 722-8446-0.004.  */
@@ -6999,7 +7028,7 @@ display_debug_frames (struct dwarf_section *section,
 		case DW_CFA_advance_loc:
 		  break;
 		case DW_CFA_offset:
-		  LEB ();
+		  SKIP_ULEB ();
 		  if (frame_need_space (fc, opa) >= 0)
 		    fc->col_type[opa] = DW_CFA_undefined;
 		  break;
@@ -7021,41 +7050,44 @@ display_debug_frames (struct dwarf_section *section,
 		  break;
 		case DW_CFA_offset_extended:
 		case DW_CFA_val_offset:
-		  reg = LEB (); LEB ();
+		  READ_ULEB (reg);
+		  SKIP_ULEB ();
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_restore_extended:
-		  reg = LEB ();
+		  READ_ULEB (reg);
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_undefined:
-		  reg = LEB ();
+		  READ_ULEB (reg);
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_same_value:
-		  reg = LEB ();
+		  READ_ULEB (reg);
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_register:
-		  reg = LEB (); LEB ();
+		  READ_ULEB (reg);
+		  SKIP_ULEB ();
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_def_cfa:
-		  LEB (); LEB ();
+		  SKIP_ULEB ();
+		  SKIP_ULEB ();
 		  break;
 		case DW_CFA_def_cfa_register:
-		  LEB ();
+		  SKIP_ULEB ();
 		  break;
 		case DW_CFA_def_cfa_offset:
-		  LEB ();
+		  SKIP_ULEB ();
 		  break;
 		case DW_CFA_def_cfa_expression:
-		  temp = LEB ();
+		  READ_ULEB (temp);
 		  new_start = start + temp;
 		  if (new_start < start)
 		    {
@@ -7067,8 +7099,8 @@ display_debug_frames (struct dwarf_section *section,
 		  break;
 		case DW_CFA_expression:
 		case DW_CFA_val_expression:
-		  reg = LEB ();
-		  temp = LEB ();
+		  READ_ULEB (reg);
+		  READ_ULEB (temp);
 		  new_start = start + temp;
 		  if (new_start < start)
 		    {
@@ -7083,24 +7115,27 @@ display_debug_frames (struct dwarf_section *section,
 		  break;
 		case DW_CFA_offset_extended_sf:
 		case DW_CFA_val_offset_sf:
-		  reg = LEB (); SLEB ();
+		  READ_ULEB (reg);
+		  SKIP_SLEB ();
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
 		case DW_CFA_def_cfa_sf:
-		  LEB (); SLEB ();
+		  SKIP_ULEB ();
+		  SKIP_SLEB ();
 		  break;
 		case DW_CFA_def_cfa_offset_sf:
-		  SLEB ();
+		  SKIP_SLEB ();
 		  break;
 		case DW_CFA_MIPS_advance_loc8:
 		  start += 8;
 		  break;
 		case DW_CFA_GNU_args_size:
-		  LEB ();
+		  SKIP_ULEB ();
 		  break;
 		case DW_CFA_GNU_negative_offset_extended:
-		  reg = LEB (); LEB ();
+		  READ_ULEB (reg);
+		  SKIP_ULEB ();
 		  if (frame_need_space (fc, reg) >= 0)
 		    fc->col_type[reg] = DW_CFA_undefined;
 		  break;
@@ -7120,8 +7155,12 @@ display_debug_frames (struct dwarf_section *section,
 	{
 	  unsigned char * tmp;
 	  unsigned op, opa;
-	  unsigned long ul, reg, roffs;
-	  dwarf_vma l;
+	  unsigned long ul, roffs;
+	  /* Note: It is tempting to use an unsigned long for 'reg' but there
+	     are various functions, notably frame_space_needed() that assume that
+	     reg is an unsigned int.  */
+	  unsigned int reg;
+	  dwarf_signed_vma l;
 	  dwarf_vma ofs;
 	  dwarf_vma vma;
 	  const char *reg_prefix = "";
@@ -7152,7 +7191,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_offset:
-	      roffs = LEB ();
+	      READ_ULEB (roffs);
 	      if (opa >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7239,8 +7278,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_offset_extended:
-	      reg = LEB ();
-	      roffs = LEB ();
+	      READ_ULEB (reg);
+	      READ_ULEB (roffs);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7255,8 +7294,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_val_offset:
-	      reg = LEB ();
-	      roffs = LEB ();
+	      READ_ULEB (reg);
+	      READ_ULEB (roffs);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7271,7 +7310,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_restore_extended:
-	      reg = LEB ();
+	      READ_ULEB (reg);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7293,7 +7332,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_undefined:
-	      reg = LEB ();
+	      READ_ULEB (reg);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7307,7 +7346,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_same_value:
-	      reg = LEB ();
+	      READ_ULEB (reg);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7321,8 +7360,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_register:
-	      reg = LEB ();
-	      roffs = LEB ();
+	      READ_ULEB (reg);
+	      READ_ULEB (roffs);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7385,8 +7424,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_def_cfa:
-	      fc->cfa_reg = LEB ();
-	      fc->cfa_offset = LEB ();
+	      READ_SLEB (fc->cfa_reg);
+	      READ_ULEB (fc->cfa_offset);
 	      fc->cfa_exp = 0;
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_def_cfa: %s ofs %d\n",
@@ -7394,7 +7433,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_def_cfa_register:
-	      fc->cfa_reg = LEB ();
+	      READ_SLEB (fc->cfa_reg);
 	      fc->cfa_exp = 0;
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_def_cfa_register: %s\n",
@@ -7402,7 +7441,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_def_cfa_offset:
-	      fc->cfa_offset = LEB ();
+	      READ_ULEB (fc->cfa_offset);
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset);
 	      break;
@@ -7413,7 +7452,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_def_cfa_expression:
-	      ul = LEB ();
+	      READ_ULEB (ul);
 	      if (start >= block_end || ul > (unsigned long) (block_end - start))
 		{
 		  printf (_("  DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul);
@@ -7431,8 +7470,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_expression:
-	      reg = LEB ();
-	      ul = LEB ();
+	      READ_ULEB (reg);
+	      READ_ULEB (ul);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      /* PR 17512: file: 069-133014-0.006.  */
@@ -7457,8 +7496,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_val_expression:
-	      reg = LEB ();
-	      ul = LEB ();
+	      READ_ULEB (reg);
+	      READ_ULEB (ul);
 	      if (reg >= (unsigned int) fc->ncols)
 		reg_prefix = bad_reg;
 	      tmp = start + ul;
@@ -7481,8 +7520,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_offset_extended_sf:
-	      reg = LEB ();
-	      l = SLEB ();
+	      READ_ULEB (reg);
+	      READ_SLEB (l);
 	      if (frame_need_space (fc, reg) < 0)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7497,8 +7536,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_val_offset_sf:
-	      reg = LEB ();
-	      l = SLEB ();
+	      READ_ULEB (reg);
+	      READ_SLEB (l);
 	      if (frame_need_space (fc, reg) < 0)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7513,8 +7552,8 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_def_cfa_sf:
-	      fc->cfa_reg = LEB ();
-	      fc->cfa_offset = SLEB ();
+	      READ_SLEB (fc->cfa_reg);
+	      READ_ULEB (fc->cfa_offset);
 	      fc->cfa_offset = fc->cfa_offset * fc->data_factor;
 	      fc->cfa_exp = 0;
 	      if (! do_debug_frames_interp)
@@ -7523,7 +7562,7 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_def_cfa_offset_sf:
-	      fc->cfa_offset = SLEB ();
+	      READ_ULEB (fc->cfa_offset);
 	      fc->cfa_offset *= fc->data_factor;
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_def_cfa_offset_sf: %d\n", (int) fc->cfa_offset);
@@ -7548,14 +7587,15 @@ display_debug_frames (struct dwarf_section *section,
 	      break;
 
 	    case DW_CFA_GNU_args_size:
-	      ul = LEB ();
+	      READ_ULEB (ul);
 	      if (! do_debug_frames_interp)
 		printf ("  DW_CFA_GNU_args_size: %ld\n", ul);
 	      break;
 
 	    case DW_CFA_GNU_negative_offset_extended:
-	      reg = LEB ();
-	      l = - LEB ();
+	      READ_ULEB (reg);
+	      READ_SLEB (l);
+	      l = - l;
 	      if (frame_need_space (fc, reg) < 0)
 		reg_prefix = bad_reg;
 	      if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -7592,8 +7632,6 @@ display_debug_frames (struct dwarf_section *section,
 }
 
 #undef GET
-#undef LEB
-#undef SLEB
 
 static int
 display_gdb_index (struct dwarf_section *section,


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