diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/sgs/elfdump/Makefile.com | 3 | ||||
-rw-r--r-- | usr/src/cmd/sgs/elfdump/common/_elfdump.h | 4 | ||||
-rw-r--r-- | usr/src/cmd/sgs/elfdump/common/dwarf.c | 496 | ||||
-rw-r--r-- | usr/src/cmd/sgs/elfdump/common/elfdump.c | 101 | ||||
-rw-r--r-- | usr/src/cmd/sgs/elfdump/common/elfdump.msg | 8 | ||||
-rw-r--r-- | usr/src/cmd/sgs/include/dwarf.h | 18 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/libld.msg | 4 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/unwind.c | 95 | ||||
-rw-r--r-- | usr/src/cmd/sgs/packages/common/SUNWonld-README | 1 | ||||
-rw-r--r-- | usr/src/cmd/sgs/tools/common/leb128.c | 51 |
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); } |