commit d949ff5607b9f595e0eed2ff15fbe5eb84eb3a34
Author: Nick Clifton <nickc@redhat.com>
Date:   Fri Apr 28 10:28:04 2017 +0100

    Fix heap-buffer overflow bugs caused when dumping debug information from a corrupt binary.
    
    	PR binutils/21438
    	* dwarf.c (process_extended_line_op): Do not assume that the
    	string extracted from the section is NUL terminated.
    	(fetch_indirect_string): If the string retrieved from the section
    	is not NUL terminated, return an error message.
    	(fetch_indirect_line_string): Likewise.
    	(fetch_indexed_string): Likewise.

Upstream-Status: Backport

CVE: CVE-2017-8398
Signed-off-by: Thiruvadi Rajaraman <trajaraman@mvista.com>

Index: git/binutils/dwarf.c
===================================================================
--- git.orig/binutils/dwarf.c	2017-09-20 13:40:17.148898512 +0530
+++ git/binutils/dwarf.c	2017-09-20 13:45:17.564730907 +0530
@@ -472,15 +472,20 @@
       printf (_("  Entry\tDir\tTime\tSize\tName\n"));
       printf ("   %d\t", ++state_machine_regs.last_file_entry);
 
-      name = data;
-      data += strnlen ((char *) data, end - data) + 1;
-      printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
-      data += bytes_read;
-      printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
-      data += bytes_read;
-      printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
-      data += bytes_read;
-      printf ("%s\n\n", name);
+      {
+	size_t l;
+
+	name = data;
+	l = strnlen ((char *) data, end - data);
+	data += len + 1;
+	printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+	data += bytes_read;
+	printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+	data += bytes_read;
+	printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end)));
+	data += bytes_read;
+	printf ("%.*s\n\n", (int) l, name);
+      }
 
       if (((unsigned int) (data - orig_data) != len) || data == end)
 	warn (_("DW_LNE_define_file: Bad opcode length\n"));
@@ -597,18 +602,28 @@
 fetch_indirect_string (dwarf_vma offset)
 {
   struct dwarf_section *section = &debug_displays [str].section;
+  const unsigned char * ret;
 
   if (section->start == NULL)
     return (const unsigned char *) _("<no .debug_str section>");
 
-  if (offset > section->size)
+  if (offset >= section->size)
     {
       warn (_("DW_FORM_strp offset too big: %s\n"),
 	    dwarf_vmatoa ("x", offset));
       return (const unsigned char *) _("<offset is too big>");
     }
 
-  return (const unsigned char *) section->start + offset;
+  ret = section->start + offset;
+  /* Unfortunately we cannot rely upon the .debug_str section ending with a
+     NUL byte.  Since our caller is expecting to receive a well formed C
+     string we test for the lack of a terminating byte here.  */
+  if (strnlen ((const char *) ret, section->size - offset)
+      == section->size - offset)
+    ret = (const unsigned char *)
+      _("<no NUL byte at end of .debug_str section>");
+
+  return ret; 
 }
 
 static const char *
@@ -621,6 +636,7 @@
   struct dwarf_section *str_section = &debug_displays [str_sec_idx].section;
   dwarf_vma index_offset = idx * offset_size;
   dwarf_vma str_offset;
+  const char * ret;
 
   if (index_section->start == NULL)
     return (dwo ? _("<no .debug_str_offsets.dwo section>")
@@ -628,7 +644,7 @@
 
   if (this_set != NULL)
     index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];
-  if (index_offset > index_section->size)
+  if (index_offset >= index_section->size)
     {
       warn (_("DW_FORM_GNU_str_index offset too big: %s\n"),
 	    dwarf_vmatoa ("x", index_offset));
@@ -641,14 +657,22 @@
 
   str_offset = byte_get (index_section->start + index_offset, offset_size);
   str_offset -= str_section->address;
-  if (str_offset > str_section->size)
+  if (str_offset >= str_section->size)
     {
       warn (_("DW_FORM_GNU_str_index indirect offset too big: %s\n"),
 	    dwarf_vmatoa ("x", str_offset));
       return _("<indirect index offset is too big>");
     }
 
-  return (const char *) str_section->start + str_offset;
+  ret = (const char *) str_section->start + str_offset;
+  /* Unfortunately we cannot rely upon str_section ending with a NUL byte.
+     Since our caller is expecting to receive a well formed C string we test
+     for the lack of a terminating byte here.  */
+  if (strnlen (ret, str_section->size - str_offset)
+      == str_section->size - str_offset)
+    ret = (const char *) _("<no NUL byte at end of section>");
+
+  return ret;
 }
 
 static const char *
Index: git/binutils/ChangeLog
===================================================================
--- git.orig/binutils/ChangeLog	2017-09-20 13:40:18.900898599 +0530
+++ git/binutils/ChangeLog	2017-09-20 13:48:02.976503560 +0530
@@ -10,6 +10,16 @@
        * objdump.c (dump_relocs_in_section): Check for an excessive
        number of relocs before attempting to dump them.
 
+2017-04-28  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/21438
+       * dwarf.c (process_extended_line_op): Do not assume that the
+       string extracted from the section is NUL terminated.
+       (fetch_indirect_string): If the string retrieved from the section
+       is not NUL terminated, return an error message.
+       (fetch_indirect_line_string): Likewise.
+       (fetch_indexed_string): Likewise.
+
 2017-02-14  Nick Clifton  <nickc@redhat.com>
 
 	PR binutils/21157
