Print this page
5688 ELF tools need to be more careful with dwarf data

@@ -38,10 +38,12 @@
 
 /*
  * 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 */
         int             do_swap;        /* True if object and system byte */
                                         /*      order differs */

@@ -68,16 +70,22 @@
  *      *ndx is incremented by the size of the extracted datum.
  *
  *      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;
                         uchar_t *p = (uchar_t *)&r;
 

@@ -86,11 +94,12 @@
                                 UL_ASSIGN_BSWAP_HALF(p, data);
                         else
                                 UL_ASSIGN_HALF(p, data);
 
                         (*ndx) += 2;
-                        return (r);
+                        *ret = r;
+                        return (DW_SUCCESS);
                 }
         case 4:
                 {
                         Word    r;
                         uchar_t *p = (uchar_t *)&r;

@@ -100,11 +109,12 @@
                                 UL_ASSIGN_BSWAP_WORD(p, data);
                         else
                                 UL_ASSIGN_WORD(p, data);
 
                         (*ndx) += 4;
-                        return (r);
+                        *ret = r;
+                        return (DW_SUCCESS);
                 }
 
         case 8:
                 {
                         uint64_t        r;

@@ -115,17 +125,18 @@
                                 UL_ASSIGN_BSWAP_LWORD(p, data);
                         else
                                 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 */
 }
 
 /*
  * Map a DWARF register constant to the machine register name it
  * corresponds to, formatting the result into buf.

@@ -174,11 +185,11 @@
  *
  * entry:
  *      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.
  *
  * exit:

@@ -261,14 +272,21 @@
                             loc_str, EC_XWORD(oper1), EC_XWORD(cur_pc));
                         loc_str = MSG_ORIG(MSG_STR_LOC);
                         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 */
                         dbg_print(0, MSG_ORIG(MSG_CFA_REG), PREFIX,
                             REGNAME(LOW_OP(op), rbuf1));

@@ -299,13 +317,27 @@
                 case 0x2d:              /* GNU: DW_CFA_GNU_window_save */
                         dbg_print(0, MSG_ORIG(MSG_CFA_SIMPLE), PREFIX);
                         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;
 
                 case 0x02:      /* v2: DW_CFA_advance_loc_1, 1-byte delta */

@@ -315,133 +347,319 @@
                          * Since the codes are contiguous, and the sizes are
                          * powers of 2, we can compute the word width from
                          * 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));
                         loc_str = MSG_ORIG(MSG_STR_LOC);
                         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;
 
                 case 0x06:              /* v2: DW_CFA_restore_extended, reg */
                 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 */
                         *ndx += oper1;
                         break;
 
                 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 */
                         *ndx += oper2;
                         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));
                         loc_str = MSG_ORIG(MSG_STR_LOC);
                         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;
 
                 default:

@@ -463,21 +681,25 @@
 #undef REGNAME
 #undef LOW_OP
 }
 
 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;
         cfi_state.do_swap = _elf_sys_encoding() != e_ident[EI_DATA];
         cfi_state.gotaddr = gotaddr;

@@ -494,32 +716,56 @@
                  * remaining in this section.  Note, ld(1) will terminate the
                  * processing of the .eh_frame contents for this file after a
                  * 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;
                         cieLflag = cieLflag_present = 0;
 

@@ -534,12 +780,25 @@
                         ndx += strlen(cieaugstr) + 1;
 
                         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;
 
                         dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
                             EC_XWORD(cfi_state.ciecalign),

@@ -549,13 +808,21 @@
                                 dbg_print(0, MSG_ORIG(MSG_UNW_CIEAXVAL));
 
                         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
                                          * unused padding bytes at the end, so
                                          * save the current index. Along with

@@ -567,13 +834,27 @@
                                         break;
                                 case 'P':
                                         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,
                                             MSG_ORIG(MSG_UNW_CIEAXPERSENC),
                                             ciePflag, conv_dwarf_ehe(ciePflag,

@@ -627,45 +908,96 @@
                 } else {
                         uint_t      fdelength = length;
                         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),
                                     EC_XWORD(val));
                                 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));
                                 }
                         }