aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2015-05-18 15:58:46 +0100
committerNick Clifton <nickc@redhat.com>2015-05-18 15:58:46 +0100
commitb4477bc81824800248d44f141aeaf63e00314a01 (patch)
treed2bb94c922fcbf4e860b6dd1d688644e94a825b0 /binutils
parent35d7c4317b85948f0a3e021d719811481d13fe45 (diff)
downloadfsf-binutils-gdb-b4477bc81824800248d44f141aeaf63e00314a01.zip
fsf-binutils-gdb-b4477bc81824800248d44f141aeaf63e00314a01.tar.gz
fsf-binutils-gdb-b4477bc81824800248d44f141aeaf63e00314a01.tar.bz2
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.
Diffstat (limited to 'binutils')
-rw-r--r--binutils/ChangeLog11
-rw-r--r--binutils/readelf.c2
-rw-r--r--binutils/unwind-ia64.c90
-rw-r--r--binutils/unwind-ia64.h2
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 *);