From cfd14a500e0485374596234de4db10e88ebc7618 Mon Sep 17 00:00:00 2001
From: Nick Clifton <nickc@redhat.com>
Date: Mon, 26 Jun 2017 15:25:08 +0100
Subject: [PATCH] Fix address violations when atempting to parse fuzzed
 binaries.

	PR binutils/21665
bfd	* opncls.c (get_build_id): Check that the section is beig enough
	to contain the whole note.
	* compress.c (bfd_get_full_section_contents): Check for and reject
	a section whoes size is greater than the size of the entire file.
	* elf32-v850.c (v850_elf_copy_notes): Allow for the ouput to not
	contain a notes section.

binutils* objdump.c (disassemble_section): Skip any section that is bigger
	than the entire file.

Upstream-Status: Backport 
CVE: CVE-2017-9955 #1
Signed-off-by: Armin Kuster <akuster@mvista.com>

---
 bfd/ChangeLog      | 10 ++++++++++
 bfd/compress.c     |  6 ++++++
 bfd/elf32-v850.c   |  4 +++-
 bfd/opncls.c       | 18 ++++++++++++++++--
 binutils/ChangeLog |  6 ++++++
 binutils/objdump.c |  4 ++--
 6 files changed, 43 insertions(+), 5 deletions(-)

Index: git/bfd/compress.c
===================================================================
--- git.orig/bfd/compress.c
+++ git/bfd/compress.c
@@ -239,6 +239,12 @@ bfd_get_full_section_contents (bfd *abfd
       *ptr = NULL;
       return TRUE;
     }
+  else if (bfd_get_file_size (abfd) > 0
+	   && sz > (bfd_size_type) bfd_get_file_size (abfd))
+    {
+      *ptr = NULL;
+      return FALSE;
+    }
 
   switch (sec->compress_status)
     {
Index: git/bfd/elf32-v850.c
===================================================================
--- git.orig/bfd/elf32-v850.c
+++ git/bfd/elf32-v850.c
@@ -2450,7 +2450,9 @@ v850_elf_copy_notes (bfd *ibfd, bfd *obf
 	BFD_ASSERT (bfd_malloc_and_get_section (ibfd, inotes, & icont));
 
       if ((ocont = elf_section_data (onotes)->this_hdr.contents) == NULL)
-	BFD_ASSERT (bfd_malloc_and_get_section (obfd, onotes, & ocont));
+	/* If the output is being stripped then it is possible for
+	   the notes section to disappear.  In this case do nothing.  */
+	return;
 
       /* Copy/overwrite notes from the input to the output.  */
       memcpy (ocont, icont, bfd_section_size (obfd, onotes));
Index: git/bfd/opncls.c
===================================================================
--- git.orig/bfd/opncls.c
+++ git/bfd/opncls.c
@@ -1776,6 +1776,7 @@ get_build_id (bfd *abfd)
   Elf_External_Note *enote;
   bfd_byte *contents;
   asection *sect;
+  bfd_size_type size;
 
   BFD_ASSERT (abfd);
 
@@ -1790,8 +1791,9 @@ get_build_id (bfd *abfd)
       return NULL;
     }
 
+  size = bfd_get_section_size (sect);
   /* FIXME: Should we support smaller build-id notes ?  */
-  if (bfd_get_section_size (sect) < 0x24)
+  if (size < 0x24)
     {
       bfd_set_error (bfd_error_invalid_operation);
       return NULL;
@@ -1804,6 +1806,17 @@ get_build_id (bfd *abfd)
       return NULL;
     }
 
+  /* FIXME: Paranoia - allow for compressed build-id sections.
+     Maybe we should complain if this size is different from
+     the one obtained above...  */
+  size = bfd_get_section_size (sect);
+  if (size < sizeof (Elf_External_Note))
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      free (contents);
+      return NULL;
+    }
+
   enote = (Elf_External_Note *) contents;
   inote.type = H_GET_32 (abfd, enote->type);
   inote.namesz = H_GET_32 (abfd, enote->namesz);
@@ -1815,7 +1828,8 @@ get_build_id (bfd *abfd)
   if (inote.descsz == 0
       || inote.type != NT_GNU_BUILD_ID
       || inote.namesz != 4 /* sizeof "GNU"  */
-      || strcmp (inote.namedata, "GNU") != 0)
+      || strncmp (inote.namedata, "GNU", 4) != 0
+      || size < (12 + BFD_ALIGN (inote.namesz, 4) + inote.descsz))
     {
       free (contents);
       bfd_set_error (bfd_error_invalid_operation);
Index: git/binutils/objdump.c
===================================================================
--- git.orig/binutils/objdump.c
+++ git/binutils/objdump.c
@@ -2048,7 +2048,7 @@ disassemble_section (bfd *abfd, asection
     return;
 
   datasize = bfd_get_section_size (section);
-  if (datasize == 0)
+  if (datasize == 0 || datasize >= (bfd_size_type) bfd_get_file_size (abfd))
     return;
 
   if (start_address == (bfd_vma) -1
@@ -2912,7 +2912,7 @@ dump_target_specific (bfd *abfd)
 static void
 dump_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED)
 {
-  bfd_byte *data = 0;
+  bfd_byte *data = NULL;
   bfd_size_type datasize;
   bfd_vma addr_offset;
   bfd_vma start_offset;
Index: git/bfd/ChangeLog
===================================================================
--- git.orig/bfd/ChangeLog
+++ git/bfd/ChangeLog
@@ -1,4 +1,14 @@
 2017-06-26  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/21665
+       * opncls.c (get_build_id): Check that the section is beig enough
+       to contain the whole note.
+       * compress.c (bfd_get_full_section_contents): Check for and reject
+       a section whoes size is greater than the size of the entire file.
+       * elf32-v850.c (v850_elf_copy_notes): Allow for the ouput to not
+       contain a notes section.
+
+2017-06-26  Nick Clifton  <nickc@redhat.com>
  
        PR binutils/21670
        * tekhex.c (getvalue): Check for the source pointer exceeding the
Index: git/binutils/ChangeLog
===================================================================
--- git.orig/binutils/ChangeLog
+++ git/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2017-06-26  Nick Clifton  <nickc@redhat.com>
+ 
+       PR binutils/21665
+       * objdump.c (disassemble_section): Skip any section that is bigger
+       than the entire file.
+
 2017-04-03  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/21345
