More fixes for illegal memory accesses triggered by running objdump on fuzzed binaries.
[deliverable/binutils-gdb.git] / bfd / peXXigen.c
index d0314301f673d855bcd2d47d40ead691866101a2..45f1937e9b415ce38444b6dd0f11205379125ad0 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for the generic parts of PE/PEI; the common executable parts.
-   Copyright (C) 1995-2014 Free Software Foundation, Inc.
+   Copyright (C) 1995-2015 Free Software Foundation, Inc.
    Written by Cygnus Solutions.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -149,8 +149,13 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
 
          name = _bfd_coff_internal_syment_name (abfd, in, namebuf);
          if (name == NULL)
-           /* FIXME: Return error.  */
-           abort ();
+           {
+             _bfd_error_handler (_("%B: unable to find name for empty section"),
+                                 abfd);
+             bfd_set_error (bfd_error_invalid_target);
+             return;
+           }
+
          sec = bfd_get_section_by_name (abfd, name);
          if (sec != NULL)
            in->n_scnum = sec->target_index;
@@ -170,15 +175,22 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1)
            {
              name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1);
              if (name == NULL)
-               /* FIXME: Return error.  */
-               abort ();
+               {
+                 _bfd_error_handler (_("%B: out of memory creating name for empty section"),
+                                     abfd);
+                 return;
+               }
              strcpy ((char *) name, namebuf);
            }
+
          flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD;
          sec = bfd_make_section_anyway_with_flags (abfd, name, flags);
          if (sec == NULL)
-           /* FIXME: Return error.  */
-           abort ();
+           {
+             _bfd_error_handler (_("%B: unable to create fake empty section"),
+                                 abfd);
+             return;
+           }
 
          sec->vma = 0;
          sec->lma = 0;
@@ -283,6 +295,9 @@ _bfd_XXi_swap_aux_in (bfd * abfd,
   AUXENT *ext = (AUXENT *) ext1;
   union internal_auxent *in = (union internal_auxent *) in1;
 
+  /* PR 17521: Make sure that all fields in the aux structure
+     are initialised.  */
+  memset (in, 0, sizeof * in);
   switch (in_class)
     {
     case C_FILE:
@@ -458,6 +473,7 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
   aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry);
   aouthdr_int->text_start =
     GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start);
+
 #if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
   /* PE32+ does not have data_start member!  */
   aouthdr_int->data_start =
@@ -505,11 +521,13 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
     int idx;
 
     /* PR 17512: Corrupt PE binaries can cause seg-faults.  */
-    if (a->NumberOfRvaAndSizes > 16)
+    if (a->NumberOfRvaAndSizes > IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
       {
        (*_bfd_error_handler)
          (_("%B: aout header specifies an invalid number of data-directory entries: %d"),
           abfd, a->NumberOfRvaAndSizes);
+       bfd_set_error (bfd_error_bad_value);
+
        /* Paranoia: If the number is corrupt, then assume that the
           actual entries themselves might be corrupt as well.  */
        a->NumberOfRvaAndSizes = 0;
@@ -529,6 +547,13 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
        else
          a->DataDirectory[idx].VirtualAddress = 0;
       }
+
+    while (idx < IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+      {
+       a->DataDirectory[idx].Size = 0;
+       a->DataDirectory[idx].VirtualAddress = 0;
+       idx ++;
+      }
   }
 
   if (aouthdr_int->entry)
@@ -772,7 +797,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
   {
     int idx;
 
-    for (idx = 0; idx < 16; idx++)
+    for (idx = 0; idx < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; idx++)
       {
        H_PUT_32 (abfd, extra->DataDirectory[idx].VirtualAddress,
                  aouthdr_out->DataDirectory[idx][0]);
@@ -1391,7 +1416,9 @@ pe_print_idata (bfd * abfd, void * vfile)
         break;
 
       dll = (char *) data + dll_name - adj;
-      fprintf (file, _("\n\tDLL Name: %s\n"), dll);
+      /* PR 17512 file: 078-12277-0.004.  */
+      bfd_size_type maxlen = (char *)(data + datasize) - dll - 1;
+      fprintf (file, _("\n\tDLL Name: %.*s\n"), (int) maxlen, dll);
 
       if (hint_addr != 0)
        {
@@ -1456,27 +1483,31 @@ pe_print_idata (bfd * abfd, void * vfile)
 #ifdef COFF_WITH_pex64
          for (j = 0; idx + j + 8 <= datasize; j += 8)
            {
+             bfd_size_type amt;
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
              unsigned long member_high = bfd_get_32 (abfd, data + idx + j + 4);
 
              if (!member && !member_high)
                break;
 
+             amt = member - adj;
+
              if (HighBitSet (member_high))
                fprintf (file, "\t%lx%08lx\t %4lx%08lx  <none>",
                         member_high, member,
                         WithoutHighBit (member_high), member);
              /* PR binutils/17512: Handle corrupt PE data.  */
-             else if (member - adj + 2 >= datasize)
+             else if (amt + 2 >= datasize)
                fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
              else
                {
                  int ordinal;
                  char *member_name;
 
-                 ordinal = bfd_get_16 (abfd, data + member - adj);
-                 member_name = (char *) data + member - adj + 2;
-                 fprintf (file, "\t%04lx\t %4d  %s",member, ordinal, member_name);
+                 ordinal = bfd_get_16 (abfd, data + amt);
+                 member_name = (char *) data + amt + 2;
+                 fprintf (file, "\t%04lx\t %4d  %.*s",member, ordinal,
+                          (int) (datasize - (amt + 2)), member_name);
                }
 
              /* If the time stamp is not zero, the import address
@@ -1492,27 +1523,30 @@ pe_print_idata (bfd * abfd, void * vfile)
 #else
          for (j = 0; idx + j + 4 <= datasize; j += 4)
            {
+             bfd_size_type amt;
              unsigned long member = bfd_get_32 (abfd, data + idx + j);
 
              /* Print single IMAGE_IMPORT_BY_NAME vector.  */
              if (member == 0)
                break;
 
+             amt = member - adj;
              if (HighBitSet (member))
                fprintf (file, "\t%04lx\t %4lu  <none>",
                         member, WithoutHighBit (member));
              /* PR binutils/17512: Handle corrupt PE data.  */
-             else if (member - adj + 2 >= datasize)
+             else if (amt + 2 >= datasize)
                fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
              else
                {
                  int ordinal;
                  char *member_name;
 
-                 ordinal = bfd_get_16 (abfd, data + member - adj);
-                 member_name = (char *) data + member - adj + 2;
-                 fprintf (file, "\t%04lx\t %4d  %s",
-                          member, ordinal, member_name);
+                 ordinal = bfd_get_16 (abfd, data + amt);
+                 member_name = (char *) data + amt + 2;
+                 fprintf (file, "\t%04lx\t %4d  %.*s",
+                          member, ordinal,
+                          (int) (datasize - (amt + 2)), member_name);
                }
 
              /* If the time stamp is not zero, the import address
@@ -1671,7 +1705,9 @@ pe_print_edata (bfd * abfd, void * vfile)
   bfd_fprintf_vma (abfd, file, edt.name);
 
   if ((edt.name >= adj) && (edt.name < adj + datasize))
-    fprintf (file, " %s\n", data + edt.name - adj);
+    fprintf (file, " %.*s\n",
+            (int) (datasize - (edt.name - adj)),
+            data + edt.name - adj);
   else
     fprintf (file, "(outside .edata section)\n");
 
@@ -1720,7 +1756,11 @@ pe_print_edata (bfd * abfd, void * vfile)
          edt.base);
 
   /* PR 17512: Handle corrupt PE binaries.  */
-  if (edt.eat_addr + (edt.num_functions * 4) - adj >= datasize)
+  if (edt.eat_addr + (edt.num_functions * 4) - adj >= datasize
+      /* PR 17512: file: 092b1829 */
+      || (edt.num_functions * 4) < edt.num_functions
+      /* PR 17512 file: 140-165018-0.004.  */
+      || data + edt.eat_addr - adj < data)
     fprintf (file, _("\tInvalid Export Address Table rva (0x%lx) or entry count (0x%lx)\n"),
             (long) edt.eat_addr,
             (long) edt.num_functions);
@@ -1736,11 +1776,12 @@ pe_print_edata (bfd * abfd, void * vfile)
          /* This rva is to a name (forwarding function) in our section.  */
          /* Should locate a function descriptor.  */
          fprintf (file,
-                  "\t[%4ld] +base[%4ld] %04lx %s -- %s\n",
+                  "\t[%4ld] +base[%4ld] %04lx %s -- %.*s\n",
                   (long) i,
                   (long) (i + edt.base),
                   (unsigned long) eat_member,
                   _("Forwarder RVA"),
+                  (int)(datasize - (eat_member - adj)),
                   data + eat_member - adj);
        }
       else
@@ -1761,11 +1802,16 @@ pe_print_edata (bfd * abfd, void * vfile)
           _("\n[Ordinal/Name Pointer] Table\n"));
 
   /* PR 17512: Handle corrupt PE binaries.  */
-  if (edt.npt_addr + (edt.num_names * 4) - adj >= datasize)
+  if (edt.npt_addr + (edt.num_names * 4) - adj >= datasize
+      /* PR 17512: file: bb68816e.  */
+      || edt.num_names * 4 < edt.num_names
+      || (data + edt.npt_addr - adj) < data)
     fprintf (file, _("\tInvalid Name Pointer Table rva (0x%lx) or entry count (0x%lx)\n"),
             (long) edt.npt_addr,
             (long) edt.num_names);
-  else if (edt.ot_addr + (edt.num_names * 2) - adj >= datasize)
+  /* PR 17512: file: 140-147171-0.004.  */
+  else if (edt.ot_addr + (edt.num_names * 2) - adj >= datasize
+          || data + edt.ot_addr - adj < data)
     fprintf (file, _("\tInvalid Ordinal Table rva (0x%lx) or entry count (0x%lx)\n"),
             (long) edt.ot_addr,
             (long) edt.num_names);
@@ -1786,7 +1832,8 @@ pe_print_edata (bfd * abfd, void * vfile)
        {
          char * name = (char *) data + name_ptr - adj;
 
-         fprintf (file, "\t[%4ld] %s\n", (long) ord, name);
+         fprintf (file, "\t[%4ld] %.*s\n", (long) ord,
+                  (int)((char *)(data + datasize) - name), name);
        }
     }
 
@@ -1849,6 +1896,14 @@ pe_print_pdata (bfd * abfd, void * vfile)
   if (datasize == 0)
     return TRUE;
 
+  /* PR 17512: file: 002-193900-0.004.  */
+  if (datasize < stop)
+    {
+      fprintf (file, _("Virtual size of .pdata section (%ld) larger than real size (%ld)\n"),
+              (long) stop, (long) datasize);
+      return FALSE;
+    }
+
   if (! bfd_malloc_and_get_section (abfd, section, &data))
     {
       if (data != NULL)
@@ -1958,7 +2013,11 @@ slurp_symtab (bfd *abfd, sym_cache *psc)
   if (storage < 0)
     return NULL;
   if (storage)
-    sy = (asymbol **) bfd_malloc (storage);
+    {
+      sy = (asymbol **) bfd_malloc (storage);
+      if (sy == NULL)
+       return NULL;
+    }
 
   psc->symcount = bfd_canonicalize_symtab (abfd, sy);
   if (psc->symcount < 0)
@@ -2485,7 +2544,7 @@ rsrc_print_section (bfd * abfd, void * vfile)
              /* If the extra data is all zeros then do not complain.
                 This is just padding so that the section meets the
                 page size requirements.  */
-             while (data ++ < regions.section_end)
+             while (++ data < regions.section_end)
                if (*data != 0)
                  break;
              if (data < regions.section_end)
@@ -2573,6 +2632,12 @@ pe_print_debugdata (bfd * abfd, void * vfile)
 
   dataoff = addr - section->vma;
 
+  if (size > (section->size - dataoff))
+    {
+      fprintf (file, _("The debug data size field in the data directory is too big for the section"));
+      return FALSE;
+    }
+
   fprintf (file,
           _("Type                Size     Rva      Offset\n"));
 
@@ -2875,6 +2940,16 @@ _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
           struct external_IMAGE_DEBUG_DIRECTORY *dd =
            (struct external_IMAGE_DEBUG_DIRECTORY *)(data + (addr - section->vma));
 
+         /* PR 17512: file: 0f15796a.  */
+         if (ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size + (addr - section->vma)
+             > bfd_get_section_size (section))
+           {
+             _bfd_error_handler (_("%A: Data Directory size (%lx) exceeds space left in section (%lx)"),
+                                 obfd, ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size,
+                                 bfd_get_section_size (section) - (addr - section->vma));
+             return FALSE;
+           }
+
           for (i = 0; i < ope->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size
                 / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++)
             {
@@ -2898,8 +2973,16 @@ _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
             }
 
           if (!bfd_set_section_contents (obfd, section, data, 0, section->size))
-            _bfd_error_handler (_("Failed to update file offsets in debug directory"));
+           {
+             _bfd_error_handler (_("Failed to update file offsets in debug directory"));
+             return FALSE;
+           }
         }
+      else if (section)
+       {
+         _bfd_error_handler (_("%A: Failed to read debug data section"), obfd);
+         return FALSE;
+       }
     }
 
   return TRUE;
@@ -4410,6 +4493,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo)
              }
            free (tmp_data);
          }
+       else
+         result = FALSE;
       }
   }
 #endif
This page took 0.029738 seconds and 4 git commands to generate.