summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/sgs/elfdump/Makefile.com3
-rw-r--r--usr/src/cmd/sgs/elfdump/common/_elfdump.h4
-rw-r--r--usr/src/cmd/sgs/elfdump/common/dwarf.c496
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.c101
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.msg8
-rw-r--r--usr/src/cmd/sgs/include/dwarf.h18
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.msg4
-rw-r--r--usr/src/cmd/sgs/libld/common/unwind.c95
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/cmd/sgs/tools/common/leb128.c51
10 files changed, 640 insertions, 141 deletions
diff --git a/usr/src/cmd/sgs/elfdump/Makefile.com b/usr/src/cmd/sgs/elfdump/Makefile.com
index 6f3fdeedac..b24b9ef4cb 100644
--- a/usr/src/cmd/sgs/elfdump/Makefile.com
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com
@@ -31,7 +31,7 @@ include $(SRC)/cmd/sgs/Makefile.com
COMOBJ = main.o corenote.o \
dwarf.o struct_layout.o \
struct_layout_i386.o struct_layout_amd64.o \
- struct_layout_sparc.o struct_layout_sparcv9.o
+ struct_layout_sparc.o struct_layout_sparcv9.o
COMOBJ32 = elfdump32.o fake_shdr32.o
@@ -59,7 +59,6 @@ LINTFLAGS += -x
LINTFLAGS64 += -x
CERRWARN += -_gcc=-Wno-uninitialized
-CERRWARN += -_gcc=-Wno-switch
BLTDEFS = msg.h
BLTDATA = msg.c
diff --git a/usr/src/cmd/sgs/elfdump/common/_elfdump.h b/usr/src/cmd/sgs/elfdump/common/_elfdump.h
index 401b29c2d3..db6f158f12 100644
--- a/usr/src/cmd/sgs/elfdump/common/_elfdump.h
+++ b/usr/src/cmd/sgs/elfdump/common/_elfdump.h
@@ -223,8 +223,8 @@ typedef enum {
#endif
extern corenote_ret_t corenote(Half, int, Word, const char *, Word);
-extern void dump_eh_frame(uchar_t *, size_t, uint64_t, Half e_machine,
- uchar_t *e_ident, uint64_t gotaddr);
+extern void dump_eh_frame(const char *, char *, uchar_t *, size_t, uint64_t,
+ Half e_machine, uchar_t *e_ident, uint64_t gotaddr);
extern void dump_hex_bytes(const void *, size_t, int, int, int);
extern int fake_shdr_cache32(const char *, int, Elf *, Elf32_Ehdr *,
diff --git a/usr/src/cmd/sgs/elfdump/common/dwarf.c b/usr/src/cmd/sgs/elfdump/common/dwarf.c
index d6072f51f5..d08b5bba72 100644
--- a/usr/src/cmd/sgs/elfdump/common/dwarf.c
+++ b/usr/src/cmd/sgs/elfdump/common/dwarf.c
@@ -40,6 +40,8 @@
* Data from eh_frame section used by dump_cfi()
*/
typedef struct {
+ const char *file;
+ const char *sh_name;
Half e_machine; /* ehdr->e_machine */
uchar_t *e_ident; /* ehdr->e_ident */
uint64_t sh_addr; /* Address of eh_frame section */
@@ -70,12 +72,18 @@ typedef struct {
* The requested datum is extracted, byte swapped if necessary,
* and returned.
*/
-static uint64_t
-dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
+static dwarf_error_t
+dwarf_extract_uint(uchar_t *data, size_t len, uint64_t *ndx, int size,
+ int do_swap, uint64_t *ret)
{
+ if (((*ndx + size) > len) ||
+ ((*ndx + size) < *ndx))
+ return (DW_OVERFLOW);
+
switch (size) {
case 1:
- return (data[(*ndx)++]);
+ *ret = (data[(*ndx)++]);
+ return (DW_SUCCESS);
case 2:
{
Half r;
@@ -88,7 +96,8 @@ dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
UL_ASSIGN_HALF(p, data);
(*ndx) += 2;
- return (r);
+ *ret = r;
+ return (DW_SUCCESS);
}
case 4:
{
@@ -102,7 +111,8 @@ dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
UL_ASSIGN_WORD(p, data);
(*ndx) += 4;
- return (r);
+ *ret = r;
+ return (DW_SUCCESS);
}
case 8:
@@ -117,13 +127,14 @@ dwarf_extract_uint(uchar_t *data, uint64_t *ndx, int size, int do_swap)
UL_ASSIGN_LWORD(p, data);
(*ndx) += 8;
- return (r);
+ *ret = r;
+ return (DW_SUCCESS);
}
+ default:
+ return (DW_BAD_ENCODING);
}
- /* If here, an invalid size was specified */
- assert(0);
- return (0);
+ /* NOTREACHED */
}
/*
@@ -176,7 +187,7 @@ dwarf_regname(Half mach, int regno, char *buf, size_t bufsize)
* data - Address of base of eh_frame section being processed
* off - Offset of current FDE within eh_frame
* ndx - Index of current position within current FDE
- * len - Length of eh_frame section
+ * len - Length of FDE
* state - Object, CIE, and FDE state for current request
* msg - Header message to issue before producing output.
* indent - # of indentation characters issued for each line of output.
@@ -263,10 +274,17 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
continue;
case 0x2: /* v2: DW_CFA_offset, reg, offset */
- soper = uleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ oper1 *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
- REGNAME(LOW_OP(op), rbuf1), EC_SXWORD(soper));
+ REGNAME(LOW_OP(op), rbuf1), EC_XWORD(oper1));
continue;
case 0x3: /* v2: DW_CFA_restore, reg */
@@ -301,9 +319,23 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
break;
case 0x01: /* v2: DW_CFA_set_loc, address */
- cur_pc = dwarf_ehe_extract(&data[off], ndx,
- state->cieRflag, state->e_ident, B_FALSE,
- state->sh_addr, off + *ndx, state->gotaddr);
+ switch (dwarf_ehe_extract(&data[off], len, ndx,
+ &cur_pc, state->cieRflag, state->e_ident, B_FALSE,
+ state->sh_addr, off + *ndx, state->gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC),
+ state->file, state->sh_name,
+ state->cieRflag);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
dbg_print(0, MSG_ORIG(MSG_CFA_CFASET), PREFIX,
EC_XWORD(cur_pc));
break;
@@ -317,8 +349,23 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
* the code.
*/
i = 1 << (op - 0x02);
- oper1 = dwarf_extract_uint(data + off, ndx, i,
- state->do_swap) * state->ciecalign;
+ switch (dwarf_extract_uint(data + off, len,
+ ndx, i, state->do_swap, &oper1)) {
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC),
+ state->file, state->sh_name,
+ i);
+ return;
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
+ oper1 *= state->ciecalign;
cur_pc += oper1;
dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
@@ -326,9 +373,23 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
break;
case 0x05: /* v2: DW_CFA_offset_extended,reg,off */
- oper1 = uleb_extract(&data[off], ndx);
- soper = uleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
REGNAME(oper1, rbuf1), EC_SXWORD(soper));
break;
@@ -337,34 +398,79 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
case 0x0d: /* v2: DW_CFA_def_cfa_register, reg */
case 0x08: /* v2: DW_CFA_same_value, reg */
case 0x07: /* v2: DW_CFA_undefined, reg */
- oper1 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
REGNAME(oper1, rbuf1));
break;
case 0x09: /* v2: DW_CFA_register, reg, reg */
- oper1 = uleb_extract(&data[off], ndx);
- oper2 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (uleb_extract(&data[off], ndx, len, &oper2) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
dbg_print(0, MSG_ORIG(MSG_CFA_REG_REG), PREFIX,
REGNAME(oper1, rbuf1), REGNAME(oper2, rbuf2));
break;
case 0x0c: /* v2: DW_CFA_def_cfa, reg, offset */
- oper1 = uleb_extract(&data[off], ndx);
- oper2 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (uleb_extract(&data[off], ndx, len, &oper2) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLU), PREFIX,
REGNAME(oper1, rbuf1), EC_XWORD(oper2));
break;
case 0x0e: /* v2: DW_CFA_def_cfa_offset, offset */
- oper1 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
EC_XWORD(oper1));
break;
case 0x0f: /* v3: DW_CFA_def_cfa_expression, blk */
- oper1 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
dbg_print(0, MSG_ORIG(MSG_CFA_EBLK), PREFIX,
EC_XWORD(oper1));
/* We currently do not decode the expression block */
@@ -373,8 +479,21 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
case 0x10: /* v3: DW_CFA_expression, reg, blk */
case 0x16: /* v3: DW_CFA_val_expression,reg,blk */
- oper1 = uleb_extract(&data[off], ndx);
- oper2 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (uleb_extract(&data[off], ndx, len, &oper2) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
dbg_print(0, MSG_ORIG(MSG_CFA_REG_EBLK), PREFIX,
REGNAME(oper1, rbuf1), EC_XWORD(oper2));
/* We currently do not decode the expression block */
@@ -382,47 +501,125 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
break;
case 0x11: /* v3: DW_CFA_offset_extended_sf, reg, off */
- oper1 = uleb_extract(&data[off], ndx);
- soper = sleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
REGNAME(oper1, rbuf1), EC_SXWORD(soper));
break;
case 0x12: /* v3: DW_CFA_def_cfa_sf, reg, offset */
- oper1 = uleb_extract(&data[off], ndx);
- soper = sleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
REGNAME(oper1, rbuf1), EC_SXWORD(soper));
break;
case 0x13: /* DW_CFA_def_cfa_offset_sf, offset */
- soper = sleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_LLD), PREFIX,
EC_SXWORD(soper));
break;
case 0x14: /* v3: DW_CFA_val_offset, reg, offset */
- oper1 = uleb_extract(&data[off], ndx);
- soper = uleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
REGNAME(oper1, rbuf1), EC_SXWORD(soper));
break;
case 0x15: /* v3: DW_CFA_val_offset_sf, reg, offset */
- oper1 = uleb_extract(&data[off], ndx);
- soper = sleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_REG_OFFLLD), PREFIX,
REGNAME(oper1, rbuf1), EC_SXWORD(soper));
break;
case 0x1d: /* GNU: DW_CFA_MIPS_advance_loc8, delta */
- oper1 = dwarf_extract_uint(data + off, ndx, i,
- state->do_swap) * state->ciecalign;
+ switch (dwarf_extract_uint(data + off, len,
+ ndx, 8, state->do_swap, &oper1)) {
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC),
+ state->file, state->sh_name,
+ 8);
+ return;
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
+ oper1 *= state->ciecalign;
cur_pc += oper1;
dbg_print(0, MSG_ORIG(MSG_CFA_ADV_LOC), PREFIX,
loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
@@ -430,16 +627,37 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
break;
case 0x2e: /* GNU: DW_CFA_GNU_args_size, size */
- oper1 = uleb_extract(&data[off], ndx);
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
dbg_print(0, MSG_ORIG(MSG_CFA_LLU), PREFIX,
EC_XWORD(oper1));
break;
case 0x2f: /* GNU:DW_CFA_GNU_negative_offset_extended,reg,off */
- oper1 = uleb_extract(&data[off], ndx);
- soper = -uleb_extract(&data[off], ndx) *
- state->ciedalign;
+ if (uleb_extract(&data[off], ndx, len, &oper1) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], ndx, len, &soper) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ state->file, state->sh_name);
+ return;
+ }
+ soper = -soper * state->ciedalign;
+ soper *= state->ciedalign;
dbg_print(0, MSG_ORIG(MSG_CFA_CFAOFF), PREFIX,
REGNAME(oper1, rbuf1), EC_SXWORD(soper));
break;
@@ -465,17 +683,21 @@ dump_cfi(uchar_t *data, uint64_t off, uint64_t *ndx, uint_t len,
}
void
-dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
- Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
+dump_eh_frame(const char *file, char *sh_name, uchar_t *data, size_t datasize,
+ uint64_t sh_addr, Half e_machine, uchar_t *e_ident, uint64_t gotaddr)
{
Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
dump_cfi_state_t cfi_state;
- uint64_t off, ndx;
+ uint64_t off, ndx, length, id;
uint_t cieid, cielength, cieversion, cieretaddr;
- int ciePflag, cieZflag, cieLflag, cieLflag_present;
- uint_t cieaugndx, length, id;
- char *cieaugstr;
-
+ int ciePflag = 0, cieZflag = 0, cieLflag = 0;
+ int cieLflag_present = 0;
+ uint_t cieaugndx;
+ char *cieaugstr = NULL;
+ boolean_t have_cie = B_FALSE;
+
+ cfi_state.file = file;
+ cfi_state.sh_name = sh_name;
cfi_state.e_machine = e_machine;
cfi_state.e_ident = e_ident;
cfi_state.sh_addr = sh_addr;
@@ -496,28 +718,52 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
* zero length CIE, thus any information that does follow is
* ignored by ld(1), and is therefore questionable.
*/
- length = (uint_t)dwarf_extract_uint(data + off, &ndx,
- 4, cfi_state.do_swap);
+ if (dwarf_extract_uint(data + off, datasize - off,
+ &ndx, 4, cfi_state.do_swap, &length) == DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ }
+
if (length == 0) {
dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM));
off += 4;
continue;
}
+ if (length > (datasize - off)) {
+ (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCIEFDELEN),
+ file, sh_name, EC_XWORD(length),
+ EC_XWORD(sh_addr + off));
+ /*
+ * If length is wrong, we have no means to find the
+ * next entry, just give up
+ */
+ return;
+ }
+
/*
* extract CIE id in native format
*/
- id = (uint_t)dwarf_extract_uint(data + off, &ndx,
- 4, cfi_state.do_swap);
+ if (dwarf_extract_uint(data + off, datasize - off, &ndx,
+ 4, cfi_state.do_swap, &id) == DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ }
/*
* A CIE record has an id of '0', otherwise this is a
* FDE entry and the 'id' is the CIE pointer.
*/
if (id == 0) {
- uint64_t persVal, ndx_save;
- uint_t axsize;
+ uint64_t persVal, ndx_save = 0;
+ uint64_t axsize;
+
+ have_cie = B_TRUE;
cielength = length;
cieid = id;
ciePflag = cfi_state.cieRflag = cieZflag = 0;
@@ -536,8 +782,21 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
cieversion, cieaugstr);
- cfi_state.ciecalign = uleb_extract(&data[off], &ndx);
- cfi_state.ciedalign = sleb_extract(&data[off], &ndx);
+ if (uleb_extract(&data[off], &ndx, datasize - off,
+ &cfi_state.ciecalign) == DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ }
+
+ if (sleb_extract(&data[off], &ndx, datasize - off,
+ &cfi_state.ciedalign) == DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ }
cieretaddr = data[off + ndx];
ndx += 1;
@@ -551,9 +810,17 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
for (cieaugndx = 0; cieaugstr[cieaugndx]; cieaugndx++) {
switch (cieaugstr[cieaugndx]) {
case 'z':
- axsize = uleb_extract(&data[off], &ndx);
+ if (uleb_extract(&data[off], &ndx,
+ datasize - off, &axsize) ==
+ DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ }
+
dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXSIZ),
- axsize);
+ EC_XWORD(axsize));
cieZflag = 1;
/*
* The auxiliary section can contain
@@ -569,9 +836,23 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
ciePflag = data[off + ndx];
ndx += 1;
- persVal = dwarf_ehe_extract(&data[off],
- &ndx, ciePflag, e_ident, B_FALSE,
- sh_addr, off + ndx, gotaddr);
+ switch (dwarf_ehe_extract(&data[off],
+ datasize - off, &ndx, &persVal,
+ ciePflag, e_ident, B_FALSE, sh_addr,
+ off + ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC),
+ file, sh_name, ciePflag);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
dbg_print(0,
MSG_ORIG(MSG_UNW_CIEAXPERS));
dbg_print(0,
@@ -629,30 +910,68 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
int fdecieptr = id;
uint64_t fdeaddrrange;
+ if (!have_cie) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWNOCIE), file, sh_name);
+ return;
+ }
+
dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
EC_XWORD(sh_addr + off));
dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
fdelength, fdecieptr);
- cfi_state.fdeinitloc = dwarf_ehe_extract(&data[off],
- &ndx, cfi_state.cieRflag, e_ident, B_FALSE,
- sh_addr, off + ndx, gotaddr);
- fdeaddrrange = dwarf_ehe_extract(&data[off], &ndx,
- (cfi_state.cieRflag & ~DW_EH_PE_pcrel),
- e_ident, B_FALSE, sh_addr, off + ndx, gotaddr);
+ switch (dwarf_ehe_extract(&data[off], datasize - off,
+ &ndx, &cfi_state.fdeinitloc, cfi_state.cieRflag,
+ e_ident, B_FALSE, sh_addr, off + ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
+ cfi_state.cieRflag);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
+
+ switch (dwarf_ehe_extract(&data[off], datasize - off,
+ &ndx, &fdeaddrrange,
+ (cfi_state.cieRflag & ~DW_EH_PE_pcrel), e_ident,
+ B_FALSE, sh_addr, off + ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW), file, sh_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC), file, sh_name,
+ (cfi_state.cieRflag & ~DW_EH_PE_pcrel));
+ return;
+ case DW_SUCCESS:
+ break;
+ }
dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
EC_XWORD(cfi_state.fdeinitloc),
EC_XWORD(fdeaddrrange),
EC_XWORD(cfi_state.fdeinitloc + fdeaddrrange - 1));
- if (cieaugstr[0])
+ if ((cieaugstr != NULL) && (cieaugstr[0] != '\0'))
dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXVAL));
if (cieZflag) {
uint64_t val;
uint64_t lndx;
- val = uleb_extract(&data[off], &ndx);
+ if (uleb_extract(&data[off], &ndx,
+ datasize - off, &val) == DW_OVERFLOW) {
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ }
lndx = ndx;
ndx += val;
dbg_print(0, MSG_ORIG(MSG_UNW_FDEAXSIZE),
@@ -660,10 +979,23 @@ dump_eh_frame(uchar_t *data, size_t datasize, uint64_t sh_addr,
if (val && cieLflag_present) {
uint64_t lsda;
- lsda = dwarf_ehe_extract(&data[off],
- &lndx, cieLflag, e_ident,
- B_FALSE, sh_addr, off + lndx,
- gotaddr);
+ switch (dwarf_ehe_extract(&data[off],
+ datasize - off, &lndx, &lsda,
+ cieLflag, e_ident, B_FALSE, sh_addr,
+ off + lndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, sh_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC),
+ file, sh_name, cieLflag);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
dbg_print(0,
MSG_ORIG(MSG_UNW_FDEAXLSDA),
EC_XWORD(lsda));
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c
index 408f619174..b2dd0afe1d 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c
@@ -551,7 +551,7 @@ unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr,
Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
uint64_t ndx, frame_ptr, fde_cnt, tabndx;
uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc;
- uint64_t initloc, initloc0;
+ uint64_t initloc, initloc0 = 0;
uint64_t gotaddr = 0;
int cnt;
@@ -563,6 +563,12 @@ unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr,
}
}
+ if ((data == NULL) || (datasize == 0)) {
+ (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
+ file, _cache ->c_name);
+ return;
+ }
+
/*
* Is this a .eh_frame_hdr?
*/
@@ -587,8 +593,20 @@ unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr,
dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers);
- frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc,
- ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx, gotaddr);
+ switch (dwarf_ehe_extract(data, datasize, &ndx,
+ &frame_ptr, frame_ptr_enc, ehdr->e_ident, B_TRUE,
+ shdr->sh_addr, ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr, MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, _cache->c_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr, MSG_INTL(MSG_ERR_DWBADENC),
+ file, _cache->c_name, frame_ptr_enc);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
if (eh_state->hdr_cnt == 1) {
eh_state->hdr_ndx = shndx;
eh_state->frame_ptr = frame_ptr;
@@ -598,8 +616,20 @@ unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr,
conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf),
EC_XWORD(frame_ptr));
- fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc,
- ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx, gotaddr);
+ switch (dwarf_ehe_extract(data, datasize, &ndx, &fde_cnt,
+ fde_cnt_enc, ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx,
+ gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr, MSG_INTL(MSG_ERR_DWOVRFLW),
+ file, _cache->c_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr, MSG_INTL(MSG_ERR_DWBADENC),
+ file, _cache->c_name, fde_cnt_enc);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC),
conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf),
@@ -610,18 +640,48 @@ unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr,
dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2));
for (tabndx = 0; tabndx < fde_cnt; tabndx++) {
- initloc = dwarf_ehe_extract(data, &ndx, table_enc,
- ehdr->e_ident, B_TRUE, shdr->sh_addr, ndx, gotaddr);
- /*LINTED:E_VAR_USED_BEFORE_SET*/
+ uint64_t table;
+
+ switch (dwarf_ehe_extract(data, datasize, &ndx,
+ &initloc, table_enc, ehdr->e_ident, B_TRUE,
+ shdr->sh_addr, ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW), file,
+ _cache->c_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC), file,
+ _cache->c_name, table_enc);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
if ((tabndx != 0) && (initloc0 > initloc))
(void) fprintf(stderr,
MSG_INTL(MSG_ERR_BADSORT), file,
_cache->c_name, EC_WORD(tabndx));
+ switch (dwarf_ehe_extract(data, datasize, &ndx, &table,
+ table_enc, ehdr->e_ident, B_TRUE, shdr->sh_addr,
+ ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWOVRFLW), file,
+ _cache->c_name);
+ return;
+ case DW_BAD_ENCODING:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_ERR_DWBADENC), file,
+ _cache->c_name, table_enc);
+ return;
+ case DW_SUCCESS:
+ break;
+ }
+
dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT),
EC_XWORD(initloc),
- EC_XWORD(dwarf_ehe_extract(data, &ndx,
- table_enc, ehdr->e_ident, B_TRUE, shdr->sh_addr,
- ndx, gotaddr)));
+ EC_XWORD(table));
initloc0 = initloc;
}
} else { /* Display the .eh_frame section */
@@ -637,8 +697,8 @@ unwind_eh_frame(Cache *cache, Word shndx, Word shnum, Phdr *uphdr, Ehdr *ehdr,
file, EC_WORD(shndx), _cache->c_name,
conv_ehdr_type(osabi, ehdr->e_type, 0, &inv_buf));
}
- dump_eh_frame(data, datasize, shdr->sh_addr,
- ehdr->e_machine, ehdr->e_ident, gotaddr);
+ dump_eh_frame(file, _cache->c_name, data, datasize,
+ shdr->sh_addr, ehdr->e_machine, ehdr->e_ident, gotaddr);
}
/*
@@ -736,7 +796,7 @@ unwind_exception_ranges(Cache *_cache, const char *file, int do_swap)
exception_range_entry scratch, *ent, *cur_ent = &scratch;
char index[MAXNDXSIZE];
Word i, nelts;
- Addr addr, addr0, offset = 0;
+ Addr addr, addr0 = 0, offset = 0;
Addr exc_addr = _cache->c_shdr->sh_addr;
dbg_print(0, MSG_INTL(MSG_EXR_TITLE));
@@ -763,7 +823,6 @@ unwind_exception_ranges(Cache *_cache, const char *file, int do_swap)
* that addresses grow monotonically.
*/
addr = SRELPTR(ret_addr);
- /*LINTED:E_VAR_USED_BEFORE_SET*/
if ((i != 0) && (addr0 > addr))
(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORT),
file, _cache->c_name, EC_WORD(i));
@@ -3681,6 +3740,9 @@ note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file)
do_swap, pnstate.pn_type, pnstate.pn_desc,
pnstate.pn_descsz);
switch (corenote_ret) {
+ case CORENOTE_R_OK_DUMP:
+ hexdump = 1;
+ break;
case CORENOTE_R_OK:
hexdump = 0;
break;
@@ -3698,6 +3760,13 @@ note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file)
conv_ehdr_mach(ehdr->e_machine,
0, &inv_buf));
break;
+ case CORENOTE_R_BADTYPE:
+ (void) fprintf(stderr,
+ MSG_INTL(MSG_NOTE_BADCORETYPE),
+ file,
+ EC_WORD(pnstate.pn_type));
+ break;
+
}
}
@@ -4918,6 +4987,8 @@ regular(const char *file, int fd, Elf *elf, uint_t flags,
&shnum, &flags) == 0)
return (ret);
break;
+ case CACHE_OK:
+ break;
case CACHE_FAIL:
return (ret);
}
diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.msg b/usr/src/cmd/sgs/elfdump/common/elfdump.msg
index 62aeab5d73..5803355c83 100644
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg
@@ -161,6 +161,7 @@
range (0 - %d): %d\n";
@ MSG_ERR_BADSIDYNTAG "%s: [%d: %s][%d]: dynamic element \
[%d: %s][%d] should have type %s: %s\n";
+@ MSG_ERR_BADCIEFDELEN "%s: %s: invalid CIE/FDE length: %#llx at %#llx\n"
@ MSG_WARN_INVINTERP1 "%s: PT_INTERP header has no associated section\n"
@@ -181,6 +182,10 @@
@ MSG_INFO_LINUXOSABI "%s: %s object has Linux .note.ABI-tag section. \
Assuming %s\n"
+@ MSG_ERR_DWOVRFLW "%s: %s: encoded DWARF data exceeds section size\n"
+@ MSG_ERR_DWBADENC "%s: %s: bad DWARF encoding: %#x\n"
+@ MSG_ERR_DWNOCIE "%s: %s: no CIE prior to FDE\n"
+
# exception_range_entry table entries.
# TRANSLATION_NOTE - the following entries provide for a series of one or more
# standard 32-bit and 64-bit .exception_ranges table entries that align with
@@ -303,6 +308,7 @@
architecture: %s\n"
@ MSG_NOTE_BADCOREDATA "%s: elfdump core file note data truncated or \
otherwise malformed\n"
+@ MSG_NOTE_BADCORETYPE "%s: unknown note type %#x\n"
@ _END_
@@ -396,7 +402,7 @@
@ MSG_UNW_CIECALGN " codealign: %#llx dataalign: %lld \
retaddr: %d"
@ MSG_UNW_CIEAXVAL " Augmentation Data:"
-@ MSG_UNW_CIEAXSIZ " size: %d"
+@ MSG_UNW_CIEAXSIZ " size: %lld"
@ MSG_UNW_CIEAXPERS " personality:"
@ MSG_UNW_CIEAXPERSENC " encoding: 0x%02x %s"
@ MSG_UNW_CIEAXPERSRTN " routine: %#08llx"
diff --git a/usr/src/cmd/sgs/include/dwarf.h b/usr/src/cmd/sgs/include/dwarf.h
index 8bb8b75eec..75c49d0760 100644
--- a/usr/src/cmd/sgs/include/dwarf.h
+++ b/usr/src/cmd/sgs/include/dwarf.h
@@ -247,14 +247,22 @@ typedef enum _LANG {
LANG_ANSI_C_V1 = 1
} LANG;
+typedef enum {
+ DW_SUCCESS = 0,
+ DW_BAD_ENCODING,
+ DW_OVERFLOW,
+} dwarf_error_t;
+
/*
* Little Endian Base 128 (leb128) encoding/decoding routines
*/
-extern uint64_t uleb_extract(unsigned char *, uint64_t *);
-extern int64_t sleb_extract(unsigned char *, uint64_t *);
-extern uint64_t dwarf_ehe_extract(unsigned char *, uint64_t *,
- uint_t, unsigned char *, boolean_t, uint64_t,
- uint64_t, uint64_t);
+extern dwarf_error_t uleb_extract(unsigned char *, uint64_t *, size_t,
+ uint64_t *);
+extern dwarf_error_t sleb_extract(unsigned char *, uint64_t *, size_t,
+ int64_t *);
+extern dwarf_error_t dwarf_ehe_extract(unsigned char *, size_t, uint64_t *,
+ uint64_t *, uint_t, unsigned char *, boolean_t,
+ uint64_t, uint64_t, uint64_t);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/sgs/libld/common/libld.msg b/usr/src/cmd/sgs/libld/common/libld.msg
index ea111c0c2f..efc8ca048f 100644
--- a/usr/src/cmd/sgs/libld/common/libld.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.msg
@@ -474,6 +474,10 @@
@ MSG_SCN_MULTICOMDAT "file %s: section [%u]%s: cannot be susceptible to multiple \
COMDAT mechanisms: %s"
+@ MSG_SCN_DWFOVRFLW "%s: section %s: encoded DWARF data exceeds \
+ section size"
+@ MSG_SCN_DWFBADENC "%s: section %s: invalid DWARF encoding: %#x"
+
# Symbol processing errors
@ MSG_SYM_NOSECDEF "symbol '%s' in file %s has no section definition"
diff --git a/usr/src/cmd/sgs/libld/common/unwind.c b/usr/src/cmd/sgs/libld/common/unwind.c
index a506b99e06..45cf0b2a9b 100644
--- a/usr/src/cmd/sgs/libld/common/unwind.c
+++ b/usr/src/cmd/sgs/libld/common/unwind.c
@@ -537,7 +537,8 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
for (APLIST_TRAVERSE(ofl->ofl_unwind, idx, osp)) {
uchar_t *data;
size_t size;
- uint64_t off = 0;
+ uint64_t off = 0, ujunk;
+ int64_t sjunk;
uint_t cieRflag = 0, ciePflag = 0;
Shdr *shdr;
@@ -601,16 +602,40 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
/*
* calign & dalign
*/
- (void) uleb_extract(&data[off], &ndx);
- (void) sleb_extract(&data[off], &ndx);
+ if (uleb_extract(&data[off], &ndx,
+ size - off, &ujunk) == DW_OVERFLOW) {
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFOVRFLW),
+ ofl->ofl_name,
+ osp->os_name);
+ return (S_ERROR);
+ }
+
+ if (sleb_extract(&data[off], &ndx,
+ size - off, &sjunk) == DW_OVERFLOW) {
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFOVRFLW),
+ ofl->ofl_name,
+ osp->os_name);
+ return (S_ERROR);
+ }
/*
* retreg
*/
- if (cieversion == 1)
+ if (cieversion == 1) {
ndx++;
- else
- (void) uleb_extract(&data[off], &ndx);
+ } else {
+ if (uleb_extract(&data[off], &ndx,
+ size - off, &ujunk) ==
+ DW_OVERFLOW) {
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFOVRFLW),
+ ofl->ofl_name,
+ osp->os_name);
+ return (S_ERROR);
+ }
+ }
/*
* we walk through the augmentation
* section now looking for the Rflag
@@ -621,8 +646,15 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
switch (cieaugstr[cieaugndx]) {
case 'z':
/* size */
- (void) uleb_extract(&data[off],
- &ndx);
+ if (uleb_extract(&data[off],
+ &ndx, size - off, &ujunk) ==
+ DW_OVERFLOW) {
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFOVRFLW),
+ ofl->ofl_name,
+ osp->os_name);
+ return (S_ERROR);
+ }
break;
case 'P':
/* personality */
@@ -633,11 +665,26 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
* value to move on to the next
* field.
*/
- (void) dwarf_ehe_extract(
- &data[off],
- &ndx, ciePflag,
+ switch (dwarf_ehe_extract(
+ &data[off], size - off,
+ &ndx, &ujunk, ciePflag,
ofl->ofl_dehdr->e_ident, B_FALSE,
- shdr->sh_addr, off + ndx, 0);
+ shdr->sh_addr, off + ndx, 0)) {
+ case DW_OVERFLOW:
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFOVRFLW),
+ ofl->ofl_name,
+ osp->os_name);
+ return (S_ERROR);
+ case DW_BAD_ENCODING:
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFBADENC),
+ ofl->ofl_name,
+ osp->os_name, ciePflag);
+ return (S_ERROR);
+ case DW_SUCCESS:
+ break;
+ }
break;
case 'R':
/* code encoding */
@@ -661,11 +708,25 @@ ld_unwind_populate_hdr(Ofl_desc *ofl)
gotaddr =
ofl->ofl_osgot->os_shdr->sh_addr;
- initloc = dwarf_ehe_extract(&data[off],
- &ndx, cieRflag, ofl->ofl_dehdr->e_ident,
- B_FALSE,
- shdr->sh_addr, off + ndx,
- gotaddr);
+ switch (dwarf_ehe_extract(&data[off],
+ size - off, &ndx, &initloc, cieRflag,
+ ofl->ofl_dehdr->e_ident, B_FALSE,
+ shdr->sh_addr, off + ndx, gotaddr)) {
+ case DW_OVERFLOW:
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFOVRFLW),
+ ofl->ofl_name,
+ osp->os_name);
+ return (S_ERROR);
+ case DW_BAD_ENCODING:
+ ld_eprintf(ofl, ERR_FATAL,
+ MSG_INTL(MSG_SCN_DWFBADENC),
+ ofl->ofl_name,
+ osp->os_name, cieRflag);
+ return (S_ERROR);
+ case DW_SUCCESS:
+ break;
+ }
/*
* Ignore FDEs with initloc set to 0.
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index f303ba6053..57f41b542c 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1655,3 +1655,4 @@ Bugid Risk Synopsis
4383 libelf can't write extended sections when ELF_F_LAYOUT
4959 completely discarded merged string sections will corrupt output objects
4996 rtld _init race leads to incorrect symbol values
+5688 ELF tools need to be more careful with dwarf data
diff --git a/usr/src/cmd/sgs/tools/common/leb128.c b/usr/src/cmd/sgs/tools/common/leb128.c
index 42ed001e15..ce30be83a6 100644
--- a/usr/src/cmd/sgs/tools/common/leb128.c
+++ b/usr/src/cmd/sgs/tools/common/leb128.c
@@ -99,8 +99,8 @@
*
*/
-uint64_t
-uleb_extract(unsigned char *data, uint64_t *dotp)
+dwarf_error_t
+uleb_extract(unsigned char *data, uint64_t *dotp, size_t len, uint64_t *ret)
{
uint64_t dot = *dotp;
uint64_t res = 0;
@@ -111,6 +111,9 @@ uleb_extract(unsigned char *data, uint64_t *dotp)
data += dot;
while (more) {
+ if (dot > len)
+ return (DW_OVERFLOW);
+
/*
* Pull off lower 7 bits
*/
@@ -134,11 +137,12 @@ uleb_extract(unsigned char *data, uint64_t *dotp)
more = ((*data++) & 0x80) >> 7;
}
*dotp = dot;
- return (res);
+ *ret = res;
+ return (DW_SUCCESS);
}
-int64_t
-sleb_extract(unsigned char *data, uint64_t *dotp)
+dwarf_error_t
+sleb_extract(unsigned char *data, uint64_t *dotp, size_t len, int64_t *ret)
{
uint64_t dot = *dotp;
int64_t res = 0;
@@ -149,6 +153,9 @@ sleb_extract(unsigned char *data, uint64_t *dotp)
data += dot;
while (more) {
+ if (dot > len)
+ return (DW_OVERFLOW);
+
/*
* Pull off lower 7 bits
*/
@@ -177,8 +184,8 @@ sleb_extract(unsigned char *data, uint64_t *dotp)
* Make sure value is properly sign extended.
*/
res = (res << (64 - shift)) >> (64 - shift);
-
- return (res);
+ *ret = res;
+ return (DW_SUCCESS);
}
/*
@@ -196,10 +203,11 @@ sleb_extract(unsigned char *data, uint64_t *dotp)
* dbase - The base address to which DW_EH_PE_datarel is relative
* (if frame_hdr is false)
*/
-uint64_t
-dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
- unsigned char *eident, boolean_t frame_hdr, uint64_t sh_base,
- uint64_t sh_offset, uint64_t dbase)
+dwarf_error_t
+dwarf_ehe_extract(unsigned char *data, size_t len, uint64_t *dotp,
+ uint64_t *ret, uint_t ehe_flags, unsigned char *eident,
+ boolean_t frame_hdr, uint64_t sh_base, uint64_t sh_offset,
+ uint64_t dbase)
{
uint64_t dot = *dotp;
uint_t lsb;
@@ -219,7 +227,8 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
switch (ehe_flags & 0x0f) {
case DW_EH_PE_omit:
- return (0);
+ *ret = 0;
+ return (DW_SUCCESS);
case DW_EH_PE_absptr:
fsize = wordsize;
break;
@@ -236,11 +245,12 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
fsize = 2;
break;
case DW_EH_PE_uleb128:
- return (uleb_extract(data, dotp));
+ return (uleb_extract(data, dotp, len, ret));
case DW_EH_PE_sleb128:
- return ((uint64_t)sleb_extract(data, dotp));
+ return (sleb_extract(data, dotp, len, (int64_t *)ret));
default:
- return (0);
+ *ret = 0;
+ return (DW_BAD_ENCODING);
}
if (lsb) {
@@ -253,6 +263,9 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
for (cnt = 0; cnt < fsize;
cnt++, dot++) {
uint64_t val;
+
+ if (dot > len)
+ return (DW_OVERFLOW);
val = data[dot];
result |= val << (cnt * 8);
}
@@ -264,7 +277,10 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
result = 0;
for (cnt = 0; cnt < fsize;
cnt++, dot++) {
- uint64_t val;
+ uint64_t val;
+
+ if (dot > len)
+ return (DW_OVERFLOW);
val = data[dot];
result |= val << ((fsize - cnt - 1) * 8);
}
@@ -307,5 +323,6 @@ dwarf_ehe_extract(unsigned char *data, uint64_t *dotp, uint_t ehe_flags,
((sizeof (uint64_t) - fsize) * 8);
*dotp = dot;
- return (result);
+ *ret = result;
+ return (DW_SUCCESS);
}