Skip to content

Commit b4477bc

Browse files
committed
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.
1 parent 35d7c43 commit b4477bc

File tree

4 files changed

+52
-53
lines changed

4 files changed

+52
-53
lines changed

binutils/ChangeLog

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
2015-05-18 Nick Clifton <[email protected]>
2+
3+
PR binutils/18420
4+
* ia64-unwind.c (unw_decode): Add end parameter. Pass parameter
5+
on to decode functions.
6+
(unw_devode_p2_p5): Pass end paraemter to UNW_DEC_SPILL_MASK.
7+
(UNW_DEC_SPILL_MASK): Add end parameter. Check that unw_rlen does
8+
not take us beyond the end of the buffer.
9+
* ia64-unwind.h (unw_decode): Update prototype.
10+
* readelf.c (dump_ia64_unwind): Pass end pointer to unw_decode.
11+
112
2015-05-15 H.J. Lu <[email protected]>
213

314
* readelf.c (dump_section_as_strings): Change pointers from

binutils/readelf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6735,7 +6735,7 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
67356735
if (end > aux->info + aux->info_size)
67366736
end = aux->info + aux->info_size;
67376737
for (dp = head + 8; dp < end;)
6738-
dp = unw_decode (dp, in_body, & in_body);
6738+
dp = unw_decode (dp, in_body, & in_body, end);
67396739
}
67406740

67416741
free (aux->funtab);

binutils/unwind-ia64.c

Lines changed: 39 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,22 @@ typedef bfd_vma unw_word;
349349
printf ("\t%s:spill_base(pspoff=0x10-0x%lx)\n", \
350350
fmt, 4*(unsigned long)pspoff)
351351

352-
#define UNW_DEC_SPILL_MASK(fmt, dp, arg) \
353-
do \
354-
{ \
355-
static const char *spill_type = "-frb"; \
352+
#define UNW_DEC_SPILL_MASK(fmt, dp, arg, end) \
353+
do \
354+
{ \
355+
static const char *spill_type = "-frb"; \
356356
unsigned const char *imaskp = dp; \
357-
unsigned char mask = 0; \
358-
bfd_vma insn = 0; \
359-
\
357+
unsigned char mask = 0; \
358+
bfd_vma insn = 0; \
359+
\
360+
/* PR 18420. */ \
361+
if ((dp + (unw_rlen / 4)) > end) \
362+
{ \
363+
printf ("\nERROR: unwind length too long (0x%lx > 0x%lx)\n\n",\
364+
(long) (unw_rlen / 4), (long)(end - dp)); \
365+
/* FIXME: Should we reset unw_rlen ? */ \
366+
break; \
367+
} \
360368
printf ("\t%s:spill_mask(imask=[", fmt); \
361369
for (insn = 0; insn < unw_rlen; ++insn) \
362370
{ \
@@ -533,36 +541,6 @@ typedef bfd_vma unw_word;
533541
* UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
534542
*/
535543

536-
static unw_word unw_decode_uleb128 (const unsigned char **);
537-
static const unsigned char *unw_decode_x1
538-
(const unsigned char *, unsigned int, void *);
539-
static const unsigned char *unw_decode_x2
540-
(const unsigned char *, unsigned int, void *);
541-
static const unsigned char *unw_decode_x3
542-
(const unsigned char *, unsigned int, void *);
543-
static const unsigned char *unw_decode_x4
544-
(const unsigned char *, unsigned int, void *);
545-
static const unsigned char *unw_decode_r1
546-
(const unsigned char *, unsigned int, void *);
547-
static const unsigned char *unw_decode_r2
548-
(const unsigned char *, unsigned int, void *);
549-
static const unsigned char *unw_decode_r3
550-
(const unsigned char *, unsigned int, void *);
551-
static const unsigned char *unw_decode_p1
552-
(const unsigned char *, unsigned int, void *);
553-
static const unsigned char *unw_decode_p2_p5
554-
(const unsigned char *, unsigned int, void *);
555-
static const unsigned char *unw_decode_p6
556-
(const unsigned char *, unsigned int, void *);
557-
static const unsigned char *unw_decode_p7_p10
558-
(const unsigned char *, unsigned int, void *);
559-
static const unsigned char *unw_decode_b1
560-
(const unsigned char *, unsigned int, void *);
561-
static const unsigned char *unw_decode_b2
562-
(const unsigned char *, unsigned int, void *);
563-
static const unsigned char *unw_decode_b3_x4
564-
(const unsigned char *, unsigned int, void *);
565-
566544
static unw_word
567545
unw_decode_uleb128 (const unsigned char **dpp)
568546
{
@@ -671,7 +649,8 @@ unw_decode_x4 (const unsigned char *dp, unsigned int code ATTRIBUTE_UNUSED,
671649
}
672650

673651
static const unsigned char *
674-
unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg)
652+
unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg,
653+
const unsigned char * end ATTRIBUTE_UNUSED)
675654
{
676655
int body = (code & 0x20) != 0;
677656
unw_word rlen;
@@ -682,7 +661,8 @@ unw_decode_r1 (const unsigned char *dp, unsigned int code, void *arg)
682661
}
683662

684663
static const unsigned char *
685-
unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg)
664+
unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg,
665+
const unsigned char * end ATTRIBUTE_UNUSED)
686666
{
687667
unsigned char byte1, mask, grsave;
688668
unw_word rlen;
@@ -697,7 +677,8 @@ unw_decode_r2 (const unsigned char *dp, unsigned int code, void *arg)
697677
}
698678

699679
static const unsigned char *
700-
unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg)
680+
unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg,
681+
const unsigned char * end ATTRIBUTE_UNUSED)
701682
{
702683
unw_word rlen;
703684

@@ -708,7 +689,8 @@ unw_decode_r3 (const unsigned char *dp, unsigned int code, void *arg)
708689

709690
static const unsigned char *
710691
unw_decode_p1 (const unsigned char *dp, unsigned int code,
711-
void *arg ATTRIBUTE_UNUSED)
692+
void *arg ATTRIBUTE_UNUSED,
693+
const unsigned char * end ATTRIBUTE_UNUSED)
712694
{
713695
unsigned char brmask = (code & 0x1f);
714696

@@ -718,7 +700,8 @@ unw_decode_p1 (const unsigned char *dp, unsigned int code,
718700

719701
static const unsigned char *
720702
unw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
721-
void *arg ATTRIBUTE_UNUSED)
703+
void *arg ATTRIBUTE_UNUSED,
704+
const unsigned char * end)
722705
{
723706
if ((code & 0x10) == 0)
724707
{
@@ -777,7 +760,7 @@ unw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
777760
}
778761
}
779762
else if ((code & 0x7) == 0)
780-
UNW_DEC_SPILL_MASK ("P4", dp, arg);
763+
UNW_DEC_SPILL_MASK ("P4", dp, arg, end);
781764
else if ((code & 0x7) == 1)
782765
{
783766
unw_word grmask, frmask, byte1, byte2, byte3;
@@ -797,7 +780,8 @@ unw_decode_p2_p5 (const unsigned char *dp, unsigned int code,
797780

798781
static const unsigned char *
799782
unw_decode_p6 (const unsigned char *dp, unsigned int code,
800-
void *arg ATTRIBUTE_UNUSED)
783+
void *arg ATTRIBUTE_UNUSED,
784+
const unsigned char * end ATTRIBUTE_UNUSED)
801785
{
802786
int gregs = (code & 0x10) != 0;
803787
unsigned char mask = (code & 0x0f);
@@ -810,7 +794,8 @@ unw_decode_p6 (const unsigned char *dp, unsigned int code,
810794
}
811795

812796
static const unsigned char *
813-
unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg)
797+
unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg,
798+
const unsigned char * end ATTRIBUTE_UNUSED)
814799
{
815800
unsigned char r, byte1, byte2;
816801
unw_word t, size;
@@ -984,7 +969,8 @@ unw_decode_p7_p10 (const unsigned char *dp, unsigned int code, void *arg)
984969

985970
static const unsigned char *
986971
unw_decode_b1 (const unsigned char *dp, unsigned int code,
987-
void *arg ATTRIBUTE_UNUSED)
972+
void *arg ATTRIBUTE_UNUSED,
973+
const unsigned char * end ATTRIBUTE_UNUSED)
988974
{
989975
unw_word label = (code & 0x1f);
990976

@@ -997,7 +983,8 @@ unw_decode_b1 (const unsigned char *dp, unsigned int code,
997983

998984
static const unsigned char *
999985
unw_decode_b2 (const unsigned char *dp, unsigned int code,
1000-
void *arg ATTRIBUTE_UNUSED)
986+
void *arg ATTRIBUTE_UNUSED,
987+
const unsigned char * end ATTRIBUTE_UNUSED)
1001988
{
1002989
unw_word t;
1003990

@@ -1007,7 +994,8 @@ unw_decode_b2 (const unsigned char *dp, unsigned int code,
1007994
}
1008995

1009996
static const unsigned char *
1010-
unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg)
997+
unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg,
998+
const unsigned char * end ATTRIBUTE_UNUSED)
1011999
{
10121000
unw_word t, ecount, label;
10131001

@@ -1044,7 +1032,7 @@ unw_decode_b3_x4 (const unsigned char *dp, unsigned int code, void *arg)
10441032
}
10451033

10461034
typedef const unsigned char *(*unw_decoder)
1047-
(const unsigned char *, unsigned int, void *);
1035+
(const unsigned char *, unsigned int, void *, const unsigned char *);
10481036

10491037
static const unw_decoder unw_decode_table[2][8] =
10501038
{
@@ -1074,12 +1062,12 @@ static const unw_decoder unw_decode_table[2][8] =
10741062
/* Decode one descriptor and return address of next descriptor. */
10751063
const unsigned char *
10761064
unw_decode (const unsigned char *dp, int inside_body,
1077-
void *ptr_inside_body)
1065+
void *ptr_inside_body, const unsigned char * end)
10781066
{
10791067
unw_decoder decoder;
10801068
unsigned char code;
10811069

10821070
code = *dp++;
10831071
decoder = unw_decode_table[inside_body][code >> 5];
1084-
return (*decoder) (dp, code, ptr_inside_body);
1072+
return (*decoder) (dp, code, ptr_inside_body, end);
10851073
}

binutils/unwind-ia64.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@
2929
#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000LL)
3030
#define UNW_LENGTH(x) ((x) & 0x00000000ffffffffLL)
3131

32-
extern const unsigned char *unw_decode (const unsigned char *, int, void *);
32+
extern const unsigned char *unw_decode (const unsigned char *, int, void *, const unsigned char *);

0 commit comments

Comments
 (0)