More fixes for invalid memory accesses triggered by fuzzed binaries.
authorNick Clifton <nickc@redhat.com>
Mon, 5 Jan 2015 23:13:50 +0000 (23:13 +0000)
committerNick Clifton <nickc@redhat.com>
Mon, 5 Jan 2015 23:13:50 +0000 (23:13 +0000)
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.

bfd/ChangeLog
bfd/archive.c
bfd/elf32-i386.c
bfd/elfcode.h
bfd/mach-o.c
bfd/syms.c
binutils/ChangeLog
binutils/nm.c
binutils/size.c

index 541c3294c9a23f9e04cc7f844413165b5b793938..0545a7ef0b96b55de401ba1dd50f6d0c8622b648 100644 (file)
@@ -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.
index dc5f76c83f56a2c90a7553859bde7776665b00fa..cc4c52f7be334ab873ad6bfbc8c8eb9d6eaff63c 100644 (file)
@@ -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);
index 24e3d4cc319a1a7d670e66c2cc539c238127579a..85acf0fce6d53c9e77414f56d335ae50c42c4af9 100644 (file)
@@ -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
index 481b007232e4f901c06c443218a32583ed912320..1a9d3045124fd9bb3d4c94c3c78f00977234f065 100644 (file)
@@ -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)
index 14d6276c348ee53682b481ccf31a489995318b88..5dd6250f9d64c79ce14616f4a1d10d2bce22bae7 100644 (file)
@@ -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;
index 37be5f28275cf653aec662b7cda3197b7f707fde..0b0d26ded606bed121789b225c8d938a79663325 100644 (file)
@@ -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;
index ab35da9139b732f6080b22c6516f335668a0c0fc..a43598396154f6606824a24600c1a3503f69873f 100644 (file)
@@ -1,3 +1,16 @@
+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
index bdc6078adaa66798a2ca89e369bddd54d68498d9..76013df45b0c502760bf9641a284534105b53ddb 100644 (file)
@@ -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);
     }
 }
 
 \f
-/* 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 (" ");
index 1035f2be2aa1a9a349b1263ef6866a61a436e927..465603f243dee0a1ddea3e598c0edf6fcb1fe3de 100644 (file)
@@ -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;
     }