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>
Sun, 22 Sep 2019 23:34:54 +0000 (09:04 +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.

binutils/ChangeLog
binutils/dwarf.c

index 21dc92dcae1a9b1567382845a4ff3a557821f265..a2ac2b752d949909779c04b39d7922dfcb46f6bf 100644 (file)
@@ -1,3 +1,12 @@
+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-20  Alan Modra  <amodra@gmail.com>
 
        * ar.c (write_archive): Use bfd_set_thin_archive.
index df924e4050a082b4e80d6c8a9b3870a89d767516..2fe469f060368b896720d98738f2680291c52355 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;