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

@@ -97,22 +97,25 @@
  * DW_EH_PE_indirect       0x80 bit to signal indirection after relocation
  * DW_EH_PE_omit           0xff No value is present.
  *
  */
 
-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;
         int             more = 1;
         int             shift = 0;
         int             val;
 
         data += dot;
 
         while (more) {
+                if (dot > len)
+                        return (DW_OVERFLOW);
+
                 /*
                  * Pull off lower 7 bits
                  */
                 val = (*data) & 0x7f;
 

@@ -132,25 +135,29 @@
                  * is the last byte.
                  */
                 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;
         int             more = 1;
         int             shift = 0;
         int             val;
 
         data += dot;
 
         while (more) {
+                if (dot > len)
+                        return (DW_OVERFLOW);
+
                 /*
                  * Pull off lower 7 bits
                  */
                 val = (*data) & 0x7f;
 

@@ -175,12 +182,12 @@
 
         /*
          * Make sure value is properly sign extended.
          */
         res = (res << (64 - shift)) >> (64 - shift);
-
-        return (res);
+        *ret = res;
+        return (DW_SUCCESS);
 }
 
 /*
  * Extract a DWARF encoded datum
  *

@@ -194,14 +201,15 @@
  *      sh_base - Base address of ELF section containing desired datum
  *      sh_offset - Offset relative to sh_base of desired datum.
  *      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;
         uint_t      wordsize;
         uint_t      fsize;

@@ -217,11 +225,12 @@
         else
                 wordsize = 4;
 
         switch (ehe_flags & 0x0f) {
         case DW_EH_PE_omit:
-                return (0);
+                *ret = 0;
+                return (DW_SUCCESS);
         case DW_EH_PE_absptr:
                 fsize = wordsize;
                 break;
         case DW_EH_PE_udata8:
         case DW_EH_PE_sdata8:

@@ -234,15 +243,16 @@
         case DW_EH_PE_udata2:
         case DW_EH_PE_sdata2:
                 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) {
                 /*
                  * Extract unaligned LSB formated data

@@ -251,10 +261,13 @@
 
                 result = 0;
                 for (cnt = 0; cnt < fsize;
                     cnt++, dot++) {
                         uint64_t val;
+
+                        if (dot > len)
+                                return (DW_OVERFLOW);
                         val = data[dot];
                         result |= val << (cnt * 8);
                 }
         } else {
                 /*

@@ -263,10 +276,13 @@
                 uint_t  cnt;
                 result = 0;
                 for (cnt = 0; cnt < fsize;
                     cnt++, dot++) {
                         uint64_t        val;
+
+                        if (dot > len)
+                                return (DW_OVERFLOW);
                         val = data[dot];
                         result |= val << ((fsize - cnt - 1) * 8);
                 }
         }
         /*

@@ -305,7 +321,8 @@
         /* Truncate the result to its specified size */
         result = (result << ((sizeof (uint64_t) - fsize) * 8)) >>
             ((sizeof (uint64_t) - fsize) * 8);
 
         *dotp = dot;
-        return (result);
+        *ret = result;
+        return (DW_SUCCESS);
 }