diff options
author | Nick Clifton <nickc@redhat.com> | 2015-05-18 15:58:46 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2015-05-18 15:58:46 +0100 |
commit | b4477bc81824800248d44f141aeaf63e00314a01 (patch) | |
tree | d2bb94c922fcbf4e860b6dd1d688644e94a825b0 /binutils | |
parent | 35d7c4317b85948f0a3e021d719811481d13fe45 (diff) | |
download | fsf-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/ChangeLog | 11 | ||||
-rw-r--r-- | binutils/readelf.c | 2 | ||||
-rw-r--r-- | binutils/unwind-ia64.c | 90 | ||||
-rw-r--r-- | 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 *); |