PR25018, readelf crash on 32bits
authorAlan Modra <amodra@gmail.com>
Sun, 22 Sep 2019 23:23:07 +0000 (08:53 +0930)
committerAlan Modra <amodra@gmail.com>
Wed, 25 Sep 2019 00:36:06 +0000 (10:06 +0930)
Pointer comparisons after adding an offset just don't work to catch
overflow when the offset is a larger type than the pointer.

PR 25018
* dwarf.c (get_type_signedness): Delete ineffective pointer
comparison check.  Properly range check uvalue offset on
recursive call.
(read_and_display_attr_value): Range check uvalue offset before
calling get_type_signedness.

(cherry picked from commit b3fe587ed2c78d46132bd33e14f42449d410354b)

binutils/ChangeLog
binutils/dwarf.c

index 167e937..dd22321 100644 (file)
@@ -1,3 +1,14 @@
+2019-09-25  Alan Modra  <amodra@gmail.com>
+
+       Apply from master
+       2019-09-23  Alan Modra  <amodra@gmail.com>
+       PR 25018
+       * dwarf.c (get_type_signedness): Delete ineffective pointer
+       comparison check.  Properly range check uvalue offset on
+       recursive call.
+       (read_and_display_attr_value): Range check uvalue offset before
+       calling get_type_signedness.
+
 2019-09-19  Tamar Christina  <tamar.christina@arm.com>
 
        * testsuite/binutils-all/objdump.exp (objdump -S): Update testcase.
index df924e4..2fe469f 100644 (file)
@@ -1999,9 +1999,6 @@ get_type_signedness (unsigned char *        start,
 
   * is_signed = FALSE;
 
-  if (data >= end)
-    return;
-
   abbrev_number = read_uleb128 (data, & bytes_read, end);
   data += bytes_read;
 
@@ -2042,6 +2039,8 @@ get_type_signedness (unsigned char *        start,
                 NB/ We need to avoid infinite recursion.  */
              return;
            }
+         if (uvalue >= (size_t) (end - start))
+           return;
          get_type_signedness (start, start + uvalue, end, pointer_size,
                               offset_size, dwarf_version, is_signed, TRUE);
          break;
@@ -2725,7 +2724,8 @@ read_and_display_attr_value (unsigned long           attribute,
   switch (attribute)
     {
     case DW_AT_type:
-      if (level >= 0 && level < MAX_CU_NESTING)
+      if (level >= 0 && level < MAX_CU_NESTING
+         && uvalue < (size_t) (end - start))
        {
          bfd_boolean is_signed = FALSE;