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 seg-fault in readelf when decoding corrupt IA64 unwind information.


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

commit b4477bc81824800248d44f141aeaf63e00314a01
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon May 18 15:58:46 2015 +0100

    Fix seg-fault in readelf when decoding corrupt IA64 unwind information.
    
    	PR binutils/18420
    	* ia64-unwind.c (unw_decode): Add end parameter.  Pass parameter
    	on to decode functions.
    	(unw_devode_p2_p5): Pass end paraemter to UNW_DEC_SPILL_MASK.
    	(UNW_DEC_SPILL_MASK): Add end parameter.  Check that unw_rlen does
    	not take us beyond the end of the buffer.
    	* ia64-unwind.h (unw_decode): Update prototype.
    	* readelf.c (dump_ia64_unwind): Pass end pointer to unw_decode.

Diff:
---
 binutils/ChangeLog     | 11 ++++++
 binutils/readelf.c     |  2 +-
 binutils/unwind-ia64.c | 90 ++++++++++++++++++++++----------------------------
 binutils/unwind-ia64.h |  2 +-
 4 files changed, 52 insertions(+), 53 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 4813a89..6bb1f1a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,14 @@
+2015-05-18  Nick Clifton  <nickc@redhat.com>
+
+	PR binutils/18420
+	* ia64-unwind.c (unw_decode): Add end parameter.  Pass parameter
+	on to decode functions.
+	(unw_devode_p2_p5): Pass end paraemter to UNW_DEC_SPILL_MASK.
+	(UNW_DEC_SPILL_MASK): Add end parameter.  Check that unw_rlen does
+	not take us beyond the end of the buffer.
+	* ia64-unwind.h (unw_decode): Update prototype.
+	* readelf.c (dump_ia64_unwind): Pass end pointer to unw_decode.
+
 2015-05-15  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* readelf.c (dump_section_as_strings): Change pointers from
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 6369aa9..b584db5 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -6735,7 +6735,7 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
       if (end > aux->info + aux->info_size)
 	end = aux->info + aux->info_size;
       for (dp = head + 8; dp < end;)
-	dp = unw_decode (dp, in_body, & in_body);
+	dp = unw_decode (dp, in_body, & in_body, end);
     }
 
   free (aux->funtab);
diff --git a/binutils/unwind-ia64.c b/binutils/unwind-ia64.c
index 94b80a3..c0c6acd 100644
--- a/binutils/unwind-ia64.c
+++ b/binutils/unwind-ia64.c
@@ -349,14 +349,22 @@ typedef bfd_vma unw_word;
   printf ("\t%s:spill_base(pspoff=0x10-0x%lx)\n",		\
 	  fmt, 4*(unsigned long)pspoff)
 
-#define UNW_DEC_SPILL_MASK(fmt, dp, arg)					\
-  do										\
-    {										\
-      static const char *spill_type = "-frb";					\
+#define UNW_DEC_SPILL_MASK(fmt, dp, arg, end)				\
+  do									\
+    {									\
+      static const char *spill_type = "-frb";				\
       unsigned const char *imaskp = dp;					\
-      unsigned char mask = 0;							\
-      bfd_vma insn = 0;								\
-										\
+      unsigned char mask = 0;						\
+      bfd_vma insn = 0;							\
+      									\
+      /* PR 18420.  */							\
+      if ((dp + (unw_rlen / 4)) > end)					\
+	{								\
+	  printf ("\nERROR: unwind length too long (0x%lx > 0x%lx)\n\n",\
+		  (long) (unw_rlen / 4), (long)(end - dp));		\
+	  /* FIXME: Should we reset unw_rlen ?  */			\
+	  break;							\
+	}								\
       printf ("\t%s:spill_mask(imask=[", fmt);					\
       for (insn = 0; insn < unw_rlen; ++insn)					\
 	{									\
@@ -533,36 +541,6 @@ typedef bfd_vma unw_word;
  *	UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
  */
 
-static unw_word unw_decode_uleb128 (const unsigned char **);
-static const unsigned char *unw_decode_x1
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_x2
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_x3
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_x4
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_r1
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_r2
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_r3
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_p1
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_p2_p5
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_p6
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_p7_p10
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_b1
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_b2
-  (const unsigned char *, unsigned int, void *);
-static const unsigned char *unw_decode_b3_x4
-  (const unsigned char *, unsigned int, void *);
-
 static unw_word
 unw_decode_uleb128 (const unsigned char **dpp)
 {
@@ -671,7 +649,8 @@ unw_decode_x4 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED,
 }
 
 static const unsigned char *
-unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg)
+unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   int body = (code & 0x20) != 0;
   unw_word rlen;
@@ -682,7 +661,8 @@ unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg)
 }
 
 static const unsigned char *
-unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg)
+unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unsigned char byte1, mask, grsave;
   unw_word rlen;
@@ -697,7 +677,8 @@ unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg)
 }
 
 static const unsigned char *
-unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg)
+unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unw_word rlen;
 
@@ -708,7 +689,8 @@ unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg)
 
 static const unsigned char *
 unw_decode_p1 (const unsigned char *dp, unsigned int code,
-	       void *arg ATTRIBUTE_UNUSED)
+	       void *arg ATTRIBUTE_UNUSED,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unsigned char brmask = (code & 0x1f);
 
@@ -718,7 +700,8 @@ unw_decode_p1 (const unsigned char *dp, unsigned int code,
 
 static const unsigned char *
 unw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
-		  void *arg ATTRIBUTE_UNUSED)
+		  void *arg ATTRIBUTE_UNUSED,
+		  const unsigned char * end)
 {
   if ((code & 0x10) == 0)
     {
@@ -777,7 +760,7 @@ unw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
 	}
     }
   else if ((code & 0x7) == 0)
-    UNW_DEC_SPILL_MASK ("P4", dp, arg);
+    UNW_DEC_SPILL_MASK ("P4", dp, arg, end);
   else if ((code & 0x7) == 1)
     {
       unw_word grmask, frmask, byte1, byte2, byte3;
@@ -797,7 +780,8 @@ unw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
 
 static const unsigned char *
 unw_decode_p6 (const unsigned char *dp, unsigned int code,
-	       void *arg ATTRIBUTE_UNUSED)
+	       void *arg ATTRIBUTE_UNUSED,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   int gregs = (code & 0x10) != 0;
   unsigned char mask = (code & 0x0f);
@@ -810,7 +794,8 @@ unw_decode_p6 (const unsigned char *dp, unsigned int code,
 }
 
 static const unsigned char *
-unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg)
+unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg,
+		   const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unsigned char r, byte1, byte2;
   unw_word t, size;
@@ -984,7 +969,8 @@ unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg)
 
 static const unsigned char *
 unw_decode_b1 (const unsigned char *dp, unsigned int code,
-	       void *arg ATTRIBUTE_UNUSED)
+	       void *arg ATTRIBUTE_UNUSED,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unw_word label = (code & 0x1f);
 
@@ -997,7 +983,8 @@ unw_decode_b1 (const unsigned char *dp, unsigned int code,
 
 static const unsigned char *
 unw_decode_b2 (const unsigned char *dp, unsigned int code,
-	       void *arg ATTRIBUTE_UNUSED)
+	       void *arg ATTRIBUTE_UNUSED,
+	       const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unw_word t;
 
@@ -1007,7 +994,8 @@ unw_decode_b2 (const unsigned char *dp, unsigned int code,
 }
 
 static const unsigned char *
-unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg)
+unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg,
+		  const unsigned char * end ATTRIBUTE_UNUSED)
 {
   unw_word t, ecount, label;
 
@@ -1044,7 +1032,7 @@ unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg)
 }
 
 typedef const unsigned char *(*unw_decoder)
-     (const unsigned char *, unsigned int, void *);
+  (const unsigned char *, unsigned int, void *, const unsigned char *);
 
 static const unw_decoder unw_decode_table[2][8] =
   {
@@ -1074,12 +1062,12 @@ static const unw_decoder unw_decode_table[2][8] =
 /* Decode one descriptor and return address of next descriptor.  */
 const unsigned char *
 unw_decode (const unsigned char *dp, int inside_body,
-	    void *ptr_inside_body)
+	    void *ptr_inside_body, const unsigned char * end)
 {
   unw_decoder decoder;
   unsigned char code;
 
   code = *dp++;
   decoder = unw_decode_table[inside_body][code >> 5];
-  return (*decoder) (dp, code, ptr_inside_body);
+  return (*decoder) (dp, code, ptr_inside_body, end);
 }
diff --git a/binutils/unwind-ia64.h b/binutils/unwind-ia64.h
index 6fc1712..15d1b7b 100644
--- a/binutils/unwind-ia64.h
+++ b/binutils/unwind-ia64.h
@@ -29,4 +29,4 @@
 #define UNW_FLAG_UHANDLER(x)	((x) & 0x0000000200000000LL)
 #define UNW_LENGTH(x)		((x) & 0x00000000ffffffffLL)
 
-extern const unsigned char *unw_decode (const unsigned char *, int, void *);
+extern const unsigned char *unw_decode (const unsigned char *, int, void *, const unsigned char *);


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