[binutils-gdb/binutils-2_29-branch] Import patch from mainline to fix address violation errors when parsing corrupt ELF binaries.

Nick Clifton nickc@sourceware.org
Mon Sep 4 16:06:00 GMT 2017


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d6f8dea6798528de0fc762409595251eeeb1f547

commit d6f8dea6798528de0fc762409595251eeeb1f547
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Sep 4 17:05:17 2017 +0100

    Import patch from mainline to fix address violation errors when parsing corrupt ELF binaries.
    
    	PR 21916
    	* elf-attrs.c (_bfd_elf_parse_attributes): Complain about very
    	small section lengths.
    	* elf.c (_bfd_elf_setup_sections): Skip empty entries in the group
    	table.
    	(elfcore_grok_freebsd_prstatus): Add checks to make sure that
    	there is enough data present in the note.

Diff:
---
 bfd/ChangeLog   |   8 ++++
 bfd/elf-attrs.c |   6 +++
 bfd/elf.c       | 125 ++++++++++++++++++++++++++++++++++----------------------
 3 files changed, 90 insertions(+), 49 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 870962c..226aea9 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -52,6 +52,14 @@
 	16-bit absolute branches into 10-bit pc-relative branches on the
 	MSP430 as well as the MSP430X.
 
+	PR 21916
+	* elf-attrs.c (_bfd_elf_parse_attributes): Complain about very
+	small section lengths.
+	* elf.c (_bfd_elf_setup_sections): Skip empty entries in the group
+	table.
+	(elfcore_grok_freebsd_prstatus): Add checks to make sure that
+	there is enough data present in the note.
+
 2017-09-04  Alan Modra  <amodra@gmail.com>
 
 	PR 22067
diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c
index 0210543..761a4ce 100644
--- a/bfd/elf-attrs.c
+++ b/bfd/elf-attrs.c
@@ -470,6 +470,12 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
 	  if (section_len > len)
 	    section_len = len;
 	  len -= section_len;
+	  if (section_len <= 4)
+	    {
+	      _bfd_error_handler (_("%B: error: attribute section length too small: %ld"),
+				  abfd, section_len);
+	      break;
+	    }
 	  section_len -= 4;
 	  namelen = strnlen ((char *) p, section_len) + 1;
 	  if (namelen == 0 || namelen >= section_len)
diff --git a/bfd/elf.c b/bfd/elf.c
index fbf639b..bbaab26 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -742,12 +742,22 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
 	{
 	  Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
 	  Elf_Internal_Group *idx;
-	  unsigned int n_elt;
+	  bfd_size_type n_elt;
 
 	  if (shdr == NULL)
 	    continue;
 
 	  idx = (Elf_Internal_Group *) shdr->contents;
+	  if (idx == NULL || shdr->sh_size < 4)
+	    {
+	      /* See PR 21957 for a reproducer.  */
+	      /* xgettext:c-format */
+	      _bfd_error_handler (_("%B: group section '%A' has no contents"),
+				  abfd, shdr->bfd_section);
+	      elf_tdata (abfd)->group_sect_ptr[i] = NULL;
+	      bfd_set_error (bfd_error_bad_value);
+	      return FALSE;
+	    }
 	  n_elt = shdr->sh_size / 4;
 
 	  /* Look through this group's sections to see if current
@@ -896,32 +906,39 @@ _bfd_elf_setup_sections (bfd *abfd)
       n_elt = shdr->sh_size / 4;
 
       while (--n_elt != 0)
-	if ((++idx)->shdr->bfd_section)
-	  elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section;
-	else if (idx->shdr->sh_type == SHT_RELA
-		 || idx->shdr->sh_type == SHT_REL)
-	  /* We won't include relocation sections in section groups in
-	     output object files. We adjust the group section size here
-	     so that relocatable link will work correctly when
-	     relocation sections are in section group in input object
-	     files.  */
-	  shdr->bfd_section->size -= 4;
-	else
-	  {
-	    /* There are some unknown sections in the group.  */
-	    _bfd_error_handler
-	      /* xgettext:c-format */
-	      (_("%B: unknown type [%#x] section `%s' in group [%A]"),
-	       abfd,
-	       idx->shdr->sh_type,
-	       bfd_elf_string_from_elf_section (abfd,
-						(elf_elfheader (abfd)
-						 ->e_shstrndx),
-						idx->shdr->sh_name),
-	       shdr->bfd_section);
-	    result = FALSE;
-	  }
+	{
+	  ++ idx;
+
+	  if (idx->shdr == NULL)
+	    continue;
+	  else if (idx->shdr->bfd_section)
+	    elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section;
+	  else if (idx->shdr->sh_type == SHT_RELA
+		   || idx->shdr->sh_type == SHT_REL)
+	    /* We won't include relocation sections in section groups in
+	       output object files. We adjust the group section size here
+	       so that relocatable link will work correctly when
+	       relocation sections are in section group in input object
+	       files.  */
+	    shdr->bfd_section->size -= 4;
+	  else
+	    {
+	      /* There are some unknown sections in the group.  */
+	      _bfd_error_handler
+		/* xgettext:c-format */
+		(_("%B: unknown type [%#x] section `%s' in group [%A]"),
+		 abfd,
+		 idx->shdr->sh_type,
+		 bfd_elf_string_from_elf_section (abfd,
+						  (elf_elfheader (abfd)
+						   ->e_shstrndx),
+						  idx->shdr->sh_name),
+		 shdr->bfd_section);
+	      result = FALSE;
+	    }
+	}
     }
+
   return result;
 }
 
@@ -5115,7 +5132,7 @@ elf_sort_sections (const void *arg1, const void *arg2)
    else
      adjustment = vma_offset - off_offset;
 
-   which can can be collapsed into the expression below.  */
+   which can be collapsed into the expression below.  */
 
 static file_ptr
 vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize)
@@ -8954,7 +8971,7 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect)
      such a section already exists.
    - For the multi-threaded case, a section named "NAME/PID", where
      PID is elfcore_make_pid (abfd).
-   Both pseudosections have identical contents. */
+   Both pseudosections have identical contents.  */
 bfd_boolean
 _bfd_elfcore_make_pseudosection (bfd *abfd,
 				 char *name,
@@ -9883,58 +9900,68 @@ elfcore_grok_freebsd_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
   size_t offset;
   size_t size;
+  size_t min_size;
 
-  /* Check for version 1 in pr_version. */
-  if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
-    return FALSE;
-  offset = 4;
-
-  /* Skip over pr_statussz.  */
+  /* Compute offset of pr_getregsz, skipping over pr_statussz.
+     Also compute minimum size of this note.  */
   switch (elf_elfheader (abfd)->e_ident[EI_CLASS])
     {
     case ELFCLASS32:
-      offset += 4;
+      offset = 4 + 4;
+      min_size = offset + (4 * 2) + 4 + 4 + 4;
       break;
 
     case ELFCLASS64:
-      offset += 4;	/* Padding before pr_statussz. */
-      offset += 8;
+      offset = 4 + 4 + 8;	/* Includes padding before pr_statussz.  */
+      min_size = offset + (8 * 2) + 4 + 4 + 4 + 4;
       break;
 
     default:
       return FALSE;
     }
 
-  /* Extract size of pr_reg from pr_gregsetsz.  */
-  if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32)
-    size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
-  else
-    size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset);
+  if (note->descsz < min_size)
+    return FALSE;
+
+  /* Check for version 1 in pr_version.  */
+  if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+    return FALSE;
 
-  /* Skip over pr_gregsetsz and pr_fpregsetsz. */
+  /* Extract size of pr_reg from pr_gregsetsz.  */
+  /* Skip over pr_gregsetsz and pr_fpregsetsz.  */
   if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32)
-    offset += 4 * 2;
+    {
+      size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+      offset += 4 * 2;
+    }
   else
-    offset += 8 * 2;
+    {
+      size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset);
+      offset += 8 * 2;
+    }
 
-  /* Skip over pr_osreldate. */
+  /* Skip over pr_osreldate.  */
   offset += 4;
 
-  /* Read signal from pr_cursig. */
+  /* Read signal from pr_cursig.  */
   if (elf_tdata (abfd)->core->signal == 0)
     elf_tdata (abfd)->core->signal
       = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
   offset += 4;
 
-  /* Read TID from pr_pid. */
+  /* Read TID from pr_pid.  */
   elf_tdata (abfd)->core->lwpid
       = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
   offset += 4;
 
-  /* Padding before pr_reg. */
+  /* Padding before pr_reg.  */
   if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
     offset += 4;
 
+  /* Make sure that there is enough data remaining in the note.  */
+  if ((note->descsz - offset) < size)
+    return FALSE;
+
   /* Make a ".reg/999" section and a ".reg" section.  */
   return _bfd_elfcore_make_pseudosection (abfd, ".reg",
 					  size, note->descpos + offset);



More information about the Binutils-cvs mailing list