This is the mail archive of the binutils-cvs@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb/users/hjl/linux/master] More fixes for invalid memory accesses triggered by fuzzed binaries.


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

commit 896ca0981329171639b1fe0b934393a79ef4fdfb
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Jan 5 23:13:50 2015 +0000

    More fixes for invalid memory accesses triggered by fuzzed binaries.
    
    	PR binutils/17512
    	* nm.c (print_symbol): Add 'is_synthetic' parameter.  Use it to
    	help initialize the info.elfinfo field.
    	(print_size_symbols): Add 'synth_count' parameter.  Use it to set
    	the is_synthetic parameter when calling print_symbol.
    	(print_symbols): Likewise.
    	(display_rel_file): Pass synth_count to printing function.
    	(display_archive): Break loop if the last archive displayed
    	matches the current archive.
    	* size.c (display_archive): Likewise.
    
    	* archive.c (do_slurp_bsd_armap): Make sure that the parsed sized
    	is at least big enough for the header to be read.
    	* elf32-i386.c (elf_i386_get_plt_sym_val): Skip unknown relocs.
    	* mach-o.c (bfd_mach_o_get_synthetic_symtab): Add range checks.
    	(bfd_mach_o_read_command): Prevetn duplicate error messages about
    	unrecognized commands.
    	* syms.c (_bfd_stab_section_find_nearest_line): Add range checks
    	when indexing into the string table.

Diff:
---
 bfd/ChangeLog      | 12 +++++++++
 bfd/archive.c      |  3 ++-
 bfd/elf32-i386.c   |  5 ++--
 bfd/elfcode.h      |  3 +--
 bfd/mach-o.c       | 61 +++++++++++++++++++++++++++++++++++++---------
 bfd/syms.c         | 12 +++++++++
 binutils/ChangeLog | 13 ++++++++++
 binutils/nm.c      | 71 ++++++++++++++++++++++++++++++++++++++----------------
 binutils/size.c    |  9 ++++++-
 9 files changed, 150 insertions(+), 39 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 541c329..0545a7e 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,15 @@
+2015-01-05  Nick Clifton  <nickc@redhat.com>
+
+	PR binutils/17512
+	* archive.c (do_slurp_bsd_armap): Make sure that the parsed sized
+	is at least big enough for the header to be read.
+	* elf32-i386.c (elf_i386_get_plt_sym_val): Skip unknown relocs.
+	* mach-o.c (bfd_mach_o_get_synthetic_symtab): Add range checks.
+	(bfd_mach_o_read_command): Prevetn duplicate error messages about
+	unrecognized commands.
+	* syms.c (_bfd_stab_section_find_nearest_line): Add range checks
+	when indexing into the string table.
+
 2015-01-01  Alan Modra  <amodra@gmail.com>
 
 	Update year range in copyright notice of all files.
diff --git a/bfd/archive.c b/bfd/archive.c
index dc5f76c..cc4c52f 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -903,7 +903,8 @@ do_slurp_bsd_armap (bfd *abfd)
   parsed_size = mapdata->parsed_size;
   free (mapdata);
   /* PR 17512: file: 883ff754.  */
-  if (parsed_size == 0)
+  /* PR 17512: file: 0458885f.  */
+  if (parsed_size < 4)
     return FALSE;
 
   raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size);
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 24e3d4c..85acf0f 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -5194,8 +5194,9 @@ bad_return:
     {
       long reloc_index;
 
-      if (p->howto->type != R_386_JUMP_SLOT
-	  && p->howto->type != R_386_IRELATIVE)
+      if (p->howto == NULL /* PR 17512: file: bc9d6cf5.  */
+	  || (p->howto->type != R_386_JUMP_SLOT
+	      && p->howto->type != R_386_IRELATIVE))
 	continue;
 
       reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset
diff --git a/bfd/elfcode.h b/bfd/elfcode.h
index 481b007..1a9d304 100644
--- a/bfd/elfcode.h
+++ b/bfd/elfcode.h
@@ -1214,10 +1214,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
       for (isym = isymbuf + 1, sym = symbase; isym < isymend; isym++, sym++)
 	{
 	  memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym));
-	  sym->symbol.the_bfd = abfd;
 
+	  sym->symbol.the_bfd = abfd;
 	  sym->symbol.name = bfd_elf_sym_name (abfd, hdr, isym, NULL);
-
 	  sym->symbol.value = isym->st_value;
 
 	  if (isym->st_shndx == SHN_UNDEF)
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 14d6276..5dd6250 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -790,18 +790,19 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd,
   bfd_mach_o_dysymtab_command *dysymtab = mdata->dysymtab;
   bfd_mach_o_symtab_command *symtab = mdata->symtab;
   asymbol *s;
+  char * s_start;
+  char * s_end;
   unsigned long count, i, j, n;
   size_t size;
   char *names;
   char *nul_name;
+  const char stub [] = "$stub";
 
   *ret = NULL;
 
   /* Stop now if no symbols or no indirect symbols.  */
-  if (dysymtab == NULL || symtab == NULL || symtab->symbols == NULL)
-    return 0;
-
-  if (dysymtab->nindirectsyms == 0)
+  if (dysymtab == NULL || dysymtab->nindirectsyms == 0
+      || symtab == NULL || symtab->symbols == NULL)
     return 0;
 
   /* We need to allocate a bfd symbol for every indirect symbol and to
@@ -811,19 +812,23 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd,
 
   for (j = 0; j < count; j++)
     {
+      const char * strng;
       unsigned int isym = dysymtab->indirect_syms[j];
 
       /* Some indirect symbols are anonymous.  */
-      if (isym < symtab->nsyms && symtab->symbols[isym].symbol.name)
-        size += strlen (symtab->symbols[isym].symbol.name) + sizeof ("$stub");
+      if (isym < symtab->nsyms && (strng = symtab->symbols[isym].symbol.name))
+	/* PR 17512: file: f5b8eeba.  */
+	size += strnlen (strng, symtab->strsize - (strng - symtab->strtab)) + sizeof (stub);
     }
 
-  s = *ret = (asymbol *) bfd_malloc (size);
+  s_start = bfd_malloc (size);
+  s = *ret = (asymbol *) s_start;
   if (s == NULL)
     return -1;
   names = (char *) (s + count);
   nul_name = names;
   *names++ = 0;
+  s_end = s_start + size;
 
   n = 0;
   for (i = 0; i < mdata->nsects; i++)
@@ -843,10 +848,19 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd,
           last = first + bfd_mach_o_section_get_nbr_indirect (abfd, sec);
           addr = sec->addr;
           entry_size = bfd_mach_o_section_get_entry_size (abfd, sec);
+
+	  /* PR 17512: file: 08e15eec.  */
+	  if (first >= count || last >= count || first > last)
+	    goto fail;
+
           for (j = first; j < last; j++)
             {
               unsigned int isym = dysymtab->indirect_syms[j];
 
+	      /* PR 17512: file: 04d64d9b.  */
+	      if (((char *) s) + sizeof (* s) > s_end)
+		goto fail;
+
               s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
               s->section = sec->bfdsection;
               s->value = addr - sec->addr;
@@ -860,10 +874,16 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd,
 
                   s->name = names;
                   len = strlen (sym);
+		  /* PR 17512: file: 47dfd4d2.  */
+		  if (names + len >= s_end)
+		    goto fail;
                   memcpy (names, sym, len);
                   names += len;
-                  memcpy (names, "$stub", sizeof ("$stub"));
-                  names += sizeof ("$stub");
+		  /* PR 17512: file: 18f340a4.  */
+		  if (names + sizeof (stub) >= s_end)
+		    goto fail;
+                  memcpy (names, stub, sizeof (stub));
+                  names += sizeof (stub);
                 }
               else
                 s->name = nul_name;
@@ -879,6 +899,11 @@ bfd_mach_o_get_synthetic_symtab (bfd *abfd,
     }
 
   return n;
+
+ fail:
+  free (s_start);
+  * ret = NULL;
+  return -1;
 }
 
 void
@@ -4660,9 +4685,21 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command)
 	return FALSE;
       break;
     default:
-      (*_bfd_error_handler)(_("%B: unknown load command 0x%lx"),
-         abfd, (unsigned long) command->type);
-      break;
+      {
+	static bfd_boolean unknown_set = FALSE;
+	static unsigned long unknown_command = 0;
+
+	/* Prevent reams of error messages when parsing corrupt binaries.  */
+	if (!unknown_set)
+	  unknown_set = TRUE;
+	else if (command->type == unknown_command)
+	  break;
+	unknown_command = command->type;
+
+	(*_bfd_error_handler)(_("%B: unknown load command 0x%lx"),
+			      abfd, (unsigned long) command->type);
+	break;
+      }
     }
 
   return TRUE;
diff --git a/bfd/syms.c b/bfd/syms.c
index 37be5f2..0b0d26d 100644
--- a/bfd/syms.c
+++ b/bfd/syms.c
@@ -823,6 +823,7 @@ _bfd_generic_read_minisymbols (bfd *abfd,
 
   *minisymsp = syms;
   *sizep = sizeof (asymbol *);
+
   return symcount;
 
  error_return:
@@ -1191,6 +1192,8 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 		{
 		  nul_fun = stab;
 		  nul_str = str;
+		  if (file_name >= (char *) info->strs + strsize)
+		    file_name = NULL;
 		  if (stab + STABSIZE + TYPEOFF < info->stabs + stabsize
 		      && *(stab + STABSIZE + TYPEOFF) == (bfd_byte) N_SO)
 		    {
@@ -1200,6 +1203,8 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 		      directory_name = file_name;
 		      file_name = ((char *) str
 				   + bfd_get_32 (abfd, stab + STRDXOFF));
+		      if (file_name >= (char *) info->strs + strsize)
+			file_name = NULL;
 		    }
 		}
 	      break;
@@ -1207,6 +1212,9 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 	    case N_SOL:
 	      /* The name of an include file.  */
 	      file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
+	      /* PR 17512: file: 0c680a1f.  */
+	      if (file_name >= (char *) info->strs + strsize)
+		file_name = NULL;
 	      break;
 
 	    case N_FUN:
@@ -1214,6 +1222,8 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 	      function_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
 	      if (function_name == (char *) str)
 		continue;
+	      if (function_name >= (char *) info->strs + strsize)
+		function_name = NULL;
 
 	      nul_fun = NULL;
 	      info->indextable[i].val = bfd_get_32 (abfd, stab + VALOFF);
@@ -1321,6 +1331,8 @@ _bfd_stab_section_find_nearest_line (bfd *abfd,
 	  if (val <= offset)
 	    {
 	      file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF);
+	      if (file_name >= (char *) info->strs + strsize)
+		file_name = NULL;
 	      *pline = 0;
 	    }
 	  break;
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index ab35da9..a435983 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,5 +1,18 @@
 2015-01-05  Nick Clifton  <nickc@redhat.com>
 
+	PR binutils/17512
+	* nm.c (print_symbol): Add 'is_synthetic' parameter.  Use it to
+	help initialize the info.elfinfo field.
+	(print_size_symbols): Add 'synth_count' parameter.  Use it to set
+	the is_synthetic parameter when calling print_symbol.
+	(print_symbols): Likewise.
+	(display_rel_file): Pass synth_count to printing function.
+	(display_archive): Break loop if the last archive displayed
+	matches the current archive.
+	* size.c (display_archive): Likewise.
+
+2015-01-05  Nick Clifton  <nickc@redhat.com>
+
 	PR binutils/17531
 	* dwarf.c (alloc_num_debug_info_entries): New variable.
 	(process_debug_info): Set it.  Use it to avoid displaying
diff --git a/binutils/nm.c b/binutils/nm.c
index bdc6078..76013df 100644
--- a/binutils/nm.c
+++ b/binutils/nm.c
@@ -806,7 +806,11 @@ get_relocs (bfd *abfd, asection *sec, void *dataarg)
 /* Print a single symbol.  */
 
 static void
-print_symbol (bfd *abfd, asymbol *sym, bfd_vma ssize, bfd *archive_bfd)
+print_symbol (bfd *        abfd,
+	      asymbol *    sym,
+	      bfd_vma      ssize,
+	      bfd *        archive_bfd,
+	      bfd_boolean  is_synthetic)
 {
   symbol_info syminfo;
   struct extended_symbol_info info;
@@ -816,12 +820,12 @@ print_symbol (bfd *abfd, asymbol *sym, bfd_vma ssize, bfd *archive_bfd)
   format->print_symbol_filename (archive_bfd, abfd);
 
   bfd_get_symbol_info (abfd, sym, &syminfo);
+
   info.sinfo = &syminfo;
   info.ssize = ssize;
-  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
-    info.elfinfo = (elf_symbol_type *) sym;
-  else
-    info.elfinfo = NULL;
+  /* Synthetic symbols do not have a full elf_symbol_type set of data available.  */
+  info.elfinfo = is_synthetic ? NULL : elf_symbol_from (abfd, sym);
+
   format->print_symbol_info (&info, abfd);
 
   if (line_numbers)
@@ -941,12 +945,17 @@ print_symbol (bfd *abfd, asymbol *sym, bfd_vma ssize, bfd *archive_bfd)
 /* Print the symbols when sorting by size.  */
 
 static void
-print_size_symbols (bfd *abfd, bfd_boolean is_dynamic,
-		    struct size_sym *symsizes, long symcount,
-		    bfd *archive_bfd)
+print_size_symbols (bfd *              abfd,
+		    bfd_boolean        is_dynamic,
+		    struct size_sym *  symsizes,
+		    long               symcount,
+		    long               synth_count,
+		    bfd *              archive_bfd)
 {
   asymbol *store;
-  struct size_sym *from, *fromend;
+  struct size_sym *from;
+  struct size_sym *fromend;
+  struct size_sym *fromsynth;
 
   store = bfd_make_empty_symbol (abfd);
   if (store == NULL)
@@ -954,6 +963,8 @@ print_size_symbols (bfd *abfd, bfd_boolean is_dynamic,
 
   from = symsizes;
   fromend = from + symcount;
+  fromsynth = symsizes + (symcount - synth_count);
+
   for (; from < fromend; from++)
     {
       asymbol *sym;
@@ -962,20 +973,34 @@ print_size_symbols (bfd *abfd, bfd_boolean is_dynamic,
       if (sym == NULL)
 	bfd_fatal (bfd_get_filename (abfd));
 
-      print_symbol (abfd, sym, from->size, archive_bfd);
+      print_symbol (abfd, sym, from->size, archive_bfd, from >= fromsynth);
     }
 }
 
 
-/* Print the symbols.  If ARCHIVE_BFD is non-NULL, it is the archive
-   containing ABFD.  */
+/* Print the symbols of ABFD that are held in MINISYMS.
+
+   If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD.
+
+   SYMCOUNT is the number of symbols in MINISYMS and SYNTH_COUNT
+   is the number of these that are synthetic.  Synthetic symbols,
+   if any are present, always come at the end of the MINISYMS.
+   
+   SIZE is the size of a symbol in MINISYMS.  */
 
 static void
-print_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms, long symcount,
-	       unsigned int size, bfd *archive_bfd)
+print_symbols (bfd *         abfd,
+	       bfd_boolean   is_dynamic,
+	       void *        minisyms,
+	       long          symcount,
+	       long          synth_count,
+	       unsigned int  size,
+	       bfd *         archive_bfd)
 {
   asymbol *store;
-  bfd_byte *from, *fromend;
+  bfd_byte *from;
+  bfd_byte *fromend;
+  bfd_byte *fromsynth;
 
   store = bfd_make_empty_symbol (abfd);
   if (store == NULL)
@@ -983,6 +1008,8 @@ print_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms, long symcount,
 
   from = (bfd_byte *) minisyms;
   fromend = from + symcount * size;
+  fromsynth = (bfd_byte *) minisyms + ((symcount - synth_count) * size);
+
   for (; from < fromend; from += size)
     {
       asymbol *sym;
@@ -991,7 +1018,7 @@ print_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms, long symcount,
       if (sym == NULL)
 	bfd_fatal (bfd_get_filename (abfd));
 
-      print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd);
+      print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd, from >= fromsynth);
     }
 }
 
@@ -1001,6 +1028,7 @@ static void
 display_rel_file (bfd *abfd, bfd *archive_bfd)
 {
   long symcount;
+  long synth_count = 0;
   void *minisyms;
   unsigned int size;
   struct size_sym *symsizes;
@@ -1031,11 +1059,10 @@ display_rel_file (bfd *abfd, bfd *archive_bfd)
       non_fatal (_("%s: no symbols"), bfd_get_filename (abfd));
       return;
     }
-
+  
   if (show_synthetic && size == sizeof (asymbol *))
     {
       asymbol *synthsyms;
-      long synth_count;
       asymbol **static_syms = NULL;
       asymbol **dyn_syms = NULL;
       long static_count = 0;
@@ -1061,6 +1088,7 @@ display_rel_file (bfd *abfd, bfd *archive_bfd)
 		bfd_fatal (bfd_get_filename (abfd));
 	    }
 	}
+
       synth_count = bfd_get_synthetic_symtab (abfd, static_count, static_syms,
 					      dyn_count, dyn_syms, &synthsyms);
       if (synth_count > 0)
@@ -1106,9 +1134,9 @@ display_rel_file (bfd *abfd, bfd *archive_bfd)
     }
 
   if (! sort_by_size)
-    print_symbols (abfd, dynamic, minisyms, symcount, size, archive_bfd);
+    print_symbols (abfd, dynamic, minisyms, symcount, synth_count, size, archive_bfd);
   else
-    print_size_symbols (abfd, dynamic, symsizes, symcount, archive_bfd);
+    print_size_symbols (abfd, dynamic, symsizes, symcount, synth_count, archive_bfd);
 
   free (minisyms);
   free (symsizes);
@@ -1181,6 +1209,8 @@ display_archive (bfd *file)
 	  bfd_close (last_arfile);
 	  lineno_cache_bfd = NULL;
 	  lineno_cache_rel_bfd = NULL;
+	  if (arfile == last_arfile)
+	    return;
 	}
       last_arfile = arfile;
     }
@@ -1434,7 +1464,6 @@ print_symbol_info_bsd (struct extended_symbol_info *info, bfd *abfd)
 	print_value (abfd, SYM_SIZE (info));
       else
 	print_value (abfd, SYM_VALUE (info));
-
       if (print_size && SYM_SIZE (info))
 	{
 	  printf (" ");
diff --git a/binutils/size.c b/binutils/size.c
index 1035f2b..465603f 100644
--- a/binutils/size.c
+++ b/binutils/size.c
@@ -365,7 +365,14 @@ display_archive (bfd *file)
       display_bfd (arfile);
 
       if (last_arfile != NULL)
-	bfd_close (last_arfile);
+	{
+	  bfd_close (last_arfile);
+
+	  /* PR 17512: file: a244edbc.  */
+	  if (last_arfile == arfile)
+	    return;
+	}
+
       last_arfile = arfile;
     }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]