More fixes for memory access errors triggered by attemps to examine corrupted binaries.
authorNick Clifton <nickc@redhat.com>
Wed, 26 Nov 2014 14:11:23 +0000 (14:11 +0000)
committerNick Clifton <nickc@redhat.com>
Wed, 26 Nov 2014 14:11:23 +0000 (14:11 +0000)
PR binutils/17512
* dwarf.c (display_block): Do nothing if the block starts after
the end of the buffer.
(read_and_display_attr_value): Add range checks.
(struct Frame_Chunk): Make the ncols and ra fields unsigned.
(frame_need_space): Test for an ncols of zero.
(read_cie): Fail if the augmentation data extends off the end of
the buffer.
(display_debug_frames): Add checks for read_cie failing.  Add
range checks.
* coff-h8300.c (rtype2howto): Replace abort with returning a NULL
value.
* coff-h8500.c (rtype2howto): Likewise.
* coff-tic30.c (rtype2howto): Likewise.
* coff-z80.c (rtype2howto): Likewise.
* coff-z8k.c (rtype2howto): Likewise.
* coff-ia64.c (RTYPE2HOWTO): Always return a valid howto.
* coff-m68k.c (m68k_rtype2howto): Return a NULL howto if none
could be found.
* coff-mcore.c (RTYPE2HOWTO): Add range checking.
* coff-w65.c (rtype2howto): Likewise.
* coff-we32k.c (RTYPE2HOWTO): Likewise.
* pe-mips.c (RTYPE2HOWTO): Likewise.
* coff-x86_64.c (coff_amd64_reloc): Likewise.  Replace abort with
an error return.
* coffcode.h (coff_slurp_reloc_table): Allow the rel parameter to
be unused.
* coffgen.c (make_a_section_from_file): Check the length of a
section name before testing to see if it is a debug section name.
(coff_object_p): Zero out any uninitialised bytes in the opt
header.
* ecoff.c (_bfd_ecoff_slurp_symbolic_info): Test for the raw
source being empty when there are values to be processed.
(_bfd_ecoff_slurp_symbol_table): Add range check.
* mach-o.c (bfd_mach_o_canonicalize_one_reloc): Likewise.
(bfd_mach_o_mangle_sections): Move test for too many sections to
before the allocation of the section table.
(bfd_mach_o_read_symtab_strtab): If the read fails, free the
memory and nullify the symbol pointer.
* reloc.c (bfd_generic_get_relocated_section_contents): Add
handling of a bfd_reloc_notsupported return value.
* versados.c (EDATA): Add range checking.
(get_record): Likewise.
(process_otr): Check for contents being available before updating
them.
(versados_canonicalize_reloc): Add range check.

21 files changed:
bfd/ChangeLog
bfd/coff-h8300.c
bfd/coff-h8500.c
bfd/coff-ia64.c
bfd/coff-m68k.c
bfd/coff-mcore.c
bfd/coff-tic30.c
bfd/coff-w65.c
bfd/coff-we32k.c
bfd/coff-x86_64.c
bfd/coff-z80.c
bfd/coff-z8k.c
bfd/coffcode.h
bfd/coffgen.c
bfd/ecoff.c
bfd/mach-o.c
bfd/pe-mips.c
bfd/reloc.c
bfd/versados.c
binutils/ChangeLog
binutils/dwarf.c

index d188bd7cefa40124df9dc548b00da6545ebf4305..c379fcae2b8def2a2142875d6feb042414dbf490 100644 (file)
@@ -1,3 +1,43 @@
+2014-11-26  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17512
+       * coff-h8300.c (rtype2howto): Replace abort with returning a NULL
+       value.
+       * coff-h8500.c (rtype2howto): Likewise.
+       * coff-tic30.c (rtype2howto): Likewise.
+       * coff-z80.c (rtype2howto): Likewise.
+       * coff-z8k.c (rtype2howto): Likewise.
+       * coff-ia64.c (RTYPE2HOWTO): Always return a valid howto.
+       * coff-m68k.c (m68k_rtype2howto): Return a NULL howto if none
+       could be found.
+       * coff-mcore.c (RTYPE2HOWTO): Add range checking.
+       * coff-w65.c (rtype2howto): Likewise.
+       * coff-we32k.c (RTYPE2HOWTO): Likewise.
+       * pe-mips.c (RTYPE2HOWTO): Likewise.
+       * coff-x86_64.c (coff_amd64_reloc): Likewise.  Replace abort with
+       an error return.
+       * coffcode.h (coff_slurp_reloc_table): Allow the rel parameter to
+       be unused.
+       * coffgen.c (make_a_section_from_file): Check the length of a
+       section name before testing to see if it is a debug section name.
+       (coff_object_p): Zero out any uninitialised bytes in the opt
+       header.
+       * ecoff.c (_bfd_ecoff_slurp_symbolic_info): Test for the raw
+       source being empty when there are values to be processed.
+       (_bfd_ecoff_slurp_symbol_table): Add range check.
+       * mach-o.c (bfd_mach_o_canonicalize_one_reloc): Likewise.
+       (bfd_mach_o_mangle_sections): Move test for too many sections to
+       before the allocation of the section table.
+       (bfd_mach_o_read_symtab_strtab): If the read fails, free the
+       memory and nullify the symbol pointer.
+       * reloc.c (bfd_generic_get_relocated_section_contents): Add
+       handling of a bfd_reloc_notsupported return value.
+       * versados.c (EDATA): Add range checking.
+       (get_record): Likewise.
+       (process_otr): Check for contents being available before updating
+       them.
+       (versados_canonicalize_reloc): Add range check.
+
 2014-11-26  Alan Modra  <amodra@gmail.com>
 
        * elf.c (_bfd_elf_slurp_version_tables): Delay allocation of
index 5ec48c960dbf7030535bfccda1c11155836df0ef..10123d3e52a396221b9e4eed39a4fe7cd25dae1a 100644 (file)
@@ -337,7 +337,7 @@ rtype2howto (arelent *internal, struct internal_reloc *dst)
       internal->howto = howto_table + 19;
       break;
     default:
-      abort ();
+      internal->howto = NULL;
       break;
     }
 }
index 574f95648b9e5042ee340bbdad49357ec438bf9e..b6a996e943a457c09a0d9c33b89ae2a68e4778f5 100644 (file)
@@ -95,7 +95,7 @@ rtype2howto (arelent * internal, struct internal_reloc *dst)
   switch (dst->r_type)
     {
     default:
-      abort ();
+      internal->howto = NULL;
       break;
     case R_H8500_IMM8:
       internal->howto = &r_imm8;
index 38a0a381f1372e3cadbc31601c7bda83ebdd695e..f1641dbbdadf5824d0a1b1416d9f7c491d9f1399 100644 (file)
@@ -47,7 +47,7 @@ static reloc_howto_type howto_table[] =
 #endif
 
 #define RTYPE2HOWTO(cache_ptr, dst) \
-           (cache_ptr)->howto = howto_table + (dst)->r_type;
+  (cache_ptr)->howto = howto_table;
 
 #ifdef COFF_WITH_PE
 /* Return TRUE if this relocation should
index f7089a681b04683789febb9a419cb7af6abf7f2c..5ebf52c3c9a866fb4f2490cefba9d2727efd1b73 100644 (file)
@@ -143,6 +143,7 @@ m68k_rtype2howto (arelent *internal, int relocentry)
     case R_PCRWORD:    internal->howto = m68kcoff_howto_table + 4; break;
     case R_PCRLONG:    internal->howto = m68kcoff_howto_table + 5; break;
     case R_RELLONG_NEG:        internal->howto = m68kcoff_howto_table + 6; break;
+    default:            internal->howto = NULL; break;
     }
 }
 
index 7dad44fdcec6c8e9ba8b18532f98cd44508322a8..9f30cfcb6236ad7ea9a1befc328e0e86fed7161c 100644 (file)
@@ -273,16 +273,15 @@ mcore_coff_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
 }
 #undef HOW2MAP
 
+#define NUM_HOWTOS NUM_ELEM (mcore_coff_howto_table)
+
 static reloc_howto_type *
 mcore_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
                              const char *r_name)
 {
   unsigned int i;
 
-  for (i = 0;
-       i < (sizeof (mcore_coff_howto_table)
-           / sizeof (mcore_coff_howto_table[0]));
-       i++)
+  for (i = 0; i < NUM_HOWTOS; i++)
     if (mcore_coff_howto_table[i].name != NULL
        && strcasecmp (mcore_coff_howto_table[i].name, r_name) == 0)
       return &mcore_coff_howto_table[i];
@@ -290,8 +289,11 @@ mcore_coff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return NULL;
 }
 
-#define RTYPE2HOWTO(cache_ptr, dst) \
-  (cache_ptr)->howto = mcore_coff_howto_table + (dst)->r_type;
+#define RTYPE2HOWTO(cache_ptr, dst)                            \
+  ((cache_ptr)->howto =                                                \
+   ((dst)->r_type < NUM_HOWTOS                                 \
+    ? mcore_coff_howto_table + (dst)->r_type                   \
+    : NULL))
 
 static reloc_howto_type *
 coff_mcore_rtype_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
@@ -303,7 +305,7 @@ coff_mcore_rtype_to_howto (bfd * abfd ATTRIBUTE_UNUSED,
 {
   reloc_howto_type * howto;
 
-  if (rel->r_type >= NUM_ELEM (mcore_coff_howto_table))
+  if (rel->r_type >= NUM_HOWTOS)
     return NULL;
 
   howto = mcore_coff_howto_table + rel->r_type;
index 740c82c867a249f9239687be4b8bcda0f5381f24..ab953088c75b7ceb90dd18e80a730e299434a973 100644 (file)
@@ -136,7 +136,7 @@ rtype2howto (arelent *internal, struct internal_reloc *dst)
       internal->howto = &tic30_coff_howto_table[4];
       break;
     default:
-      abort ();
+      internal->howto = NULL;
       break;
     }
 }
index f2087308aa1559f2c5f06fa70e7acbe479f4d373..483ae8048b5b66306ea0f833fc1891d696c04e4b 100644 (file)
 static reloc_howto_type howto_table[] =
 {
   HOWTO (R_W65_ABS8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
-    HOWTO (R_W65_ABS16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
-    HOWTO (R_W65_ABS24,   0,  2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs24", TRUE, 0x00ffffff, 0x00ffffff, FALSE),
-    HOWTO (R_W65_ABS8S8,  0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, ">abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
-    HOWTO (R_W65_ABS8S16, 0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "^abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
-    HOWTO (R_W65_ABS16S8, 1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, ">abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
-    HOWTO (R_W65_ABS16S16,1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "^abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
-    HOWTO (R_W65_PCR8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "pcrel8", TRUE, 0x000000ff, 0x000000ff, TRUE),
-    HOWTO (R_W65_PCR16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, TRUE),
-    HOWTO (R_W65_DP,      0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "dp", TRUE, 0x000000ff, 0x000000ff, FALSE),
-  };
+  HOWTO (R_W65_ABS16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
+  HOWTO (R_W65_ABS24,   0,  2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs24", TRUE, 0x00ffffff, 0x00ffffff, FALSE),
+  HOWTO (R_W65_ABS8S8,  0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, ">abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
+  HOWTO (R_W65_ABS8S16, 0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "^abs8", TRUE, 0x000000ff, 0x000000ff, FALSE),
+  HOWTO (R_W65_ABS16S8, 1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, ">abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
+  HOWTO (R_W65_ABS16S16,1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "^abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE),
+  HOWTO (R_W65_PCR8,    0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "pcrel8", TRUE, 0x000000ff, 0x000000ff, TRUE),
+  HOWTO (R_W65_PCR16,   1,  0, 16, FALSE, 0, complain_overflow_bitfield, 0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, TRUE),
+  HOWTO (R_W65_DP,      0,  0, 8,  FALSE, 0, complain_overflow_bitfield, 0, "dp", TRUE, 0x000000ff, 0x000000ff, FALSE),
+};
+
+#define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0]))
 
 /* Turn a howto into a reloc number.  */
 
@@ -61,7 +63,7 @@ static reloc_howto_type howto_table[] =
 static int
 select_reloc (reloc_howto_type *howto)
 {
-  return howto->type ;
+  return howto->type;
 }
 
 /* Code to turn a r_type into a howto ptr, uses the above howto table.  */
@@ -70,7 +72,10 @@ static void
 rtype2howto (arelent *internal,
             struct internal_reloc *dst)
 {
-  internal->howto = howto_table + dst->r_type - 1;
+  if (dst->r_type > 0 && dst->r_type <= NUM_HOWTOS)
+    internal->howto = howto_table + dst->r_type - 1;
+  else
+    internal->howto = NULL;
 }
 
 #define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry)
index d5481b8ff2ee024b67946e6fa6fb549ae4de3133..b754815e7013c6b9a0dd5db6bef2561157f974a3 100644 (file)
@@ -53,14 +53,19 @@ static reloc_howto_type howto_table[] =
   HOWTO(R_PCRLONG,            0,  2,   32, TRUE,  0, complain_overflow_signed, 0, "DISP32",   TRUE, 0xffffffff,0xffffffff, FALSE),
 };
 
+#define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0]))
+
 /* Turn a howto into a reloc  nunmber */
 
 #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
 #define BADMAG(x) WE32KBADMAG(x)
 #define WE32K  1
 
-#define RTYPE2HOWTO(cache_ptr, dst) \
-           (cache_ptr)->howto = howto_table + (dst)->r_type;
+#define RTYPE2HOWTO(cache_ptr, dst)                            \
+  ((cache_ptr)->howto =                                                \
+   ((dst)->r_type < NUM_HOWTOS                                 \
+    ? howto_table + (dst)->r_type                              \
+    : NULL))
 
 #ifndef bfd_pe_print_pdata
 #define bfd_pe_print_pdata     NULL
index 2a21bb8be691a0d9e16e923dcb52780ded361096..742adc29e03514e166d66f59db0955dbd6d8770d 100644 (file)
@@ -143,6 +143,16 @@ coff_amd64_reloc (bfd *abfd,
        reloc_howto_type *howto = reloc_entry->howto;
        unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
+       /* FIXME: We do not have an end address for data, so we cannot
+          accurately range check any addresses computed against it.
+          cf: PR binutils/17512: file: 1085-1761-0.004.
+          For now we do the best that we can.  */
+       if (addr < (unsigned char *) data || addr > ((unsigned char *) data) + input_section->size)
+         {
+           bfd_set_error (bfd_error_bad_value);
+           return bfd_reloc_notsupported;
+         }
+
        switch (howto->size)
          {
          case 0:
@@ -177,7 +187,8 @@ coff_amd64_reloc (bfd *abfd,
            break;
 
          default:
-           abort ();
+           bfd_set_error (bfd_error_bad_value);
+           return bfd_reloc_notsupported;
          }
       }
 
index 7b62cdf149e4eea6475b2281e2217a4a2210e4b0..fd68b1243429f33d04cff752c934064d3ed162c9 100644 (file)
@@ -81,7 +81,7 @@ rtype2howto (arelent *internal, struct internal_reloc *dst)
   switch (dst->r_type)
     {
     default:
-      abort ();
+      internal->howto = NULL;
       break;
     case R_IMM8:
       internal->howto = &r_imm8;
index c85713ff8dfe5eced11b4122013ba21e3473e95b..7f67ee8f5b9771c5a43d49806e3d916594da5676 100644 (file)
@@ -85,7 +85,7 @@ rtype2howto (arelent *internal, struct internal_reloc *dst)
   switch (dst->r_type)
     {
     default:
-      abort ();
+      internal->howto = NULL;
       break;
     case R_IMM8:
       internal->howto = &r_imm8;
index 9990b169ecc2329ff18f71d99992660dfb12fd34..1719b2d9008f53676cd469b68d7e01586e574443 100644 (file)
@@ -5310,7 +5310,7 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols)
 static reloc_howto_type *
 coff_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                     asection *sec ATTRIBUTE_UNUSED,
-                    struct internal_reloc *rel,
+                    struct internal_reloc *rel ATTRIBUTE_UNUSED,
                     struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
                     struct internal_syment *sym ATTRIBUTE_UNUSED,
                     bfd_vma *addendp ATTRIBUTE_UNUSED)
index 4f3f86219cc9990e692b3c4ccdf31f68ea44fa75..2b8884d3ad90c6ffa39701a63aa9f3e453766a52 100644 (file)
@@ -146,8 +146,9 @@ make_a_section_from_file (bfd *abfd,
   /* Compress/decompress DWARF debug sections with names: .debug_* and
      .zdebug_*, after the section flags is set.  */
   if ((flags & SEC_DEBUGGING)
+      && strlen (name) > 7
       && ((name[1] == 'd' && name[6] == '_')
-         || (name[1] == 'z' && name[7] == '_')))
+         || (strlen (name) > 8 && name[1] == 'z' && name[7] == '_')))
     {
       enum { nothing, compress, decompress } action = nothing;
       char *new_name = NULL;
@@ -365,6 +366,10 @@ coff_object_p (bfd *abfd)
          bfd_release (abfd, opthdr);
          return NULL;
        }
+      /* PR 17512: file: 11056-1136-0.004.  */
+      if (internal_f.f_opthdr < aoutsz)
+       memset (((char *) opthdr) + internal_f.f_opthdr, 0, aoutsz - internal_f.f_opthdr);
+
       bfd_coff_swap_aouthdr_in (abfd, opthdr, (void *) &internal_a);
       bfd_release (abfd, opthdr);
     }
index 01f51e644e416133656617c709c0206052dc4f6a..33e213491a3c5f3ef07c16f70944fd0d688d5148 100644 (file)
@@ -615,6 +615,9 @@ _bfd_ecoff_slurp_symbolic_info (bfd *abfd,
   external_fdr_size = backend->debug_swap.external_fdr_size;
   fdr_ptr = debug->fdr;
   fraw_src = (char *) debug->external_fdr;
+  /* PR 17512: file: 3372-1243-0.004.  */
+  if (fraw_src == NULL && internal_symhdr->ifdMax > 0)
+    return FALSE;
   fraw_end = fraw_src + internal_symhdr->ifdMax * external_fdr_size;
   for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
     (*backend->debug_swap.swap_fdr_in) (abfd, (void *) fraw_src, fdr_ptr);
@@ -891,6 +894,11 @@ _bfd_ecoff_slurp_symbol_table (bfd *abfd)
       EXTR internal_esym;
 
       (*swap_ext_in) (abfd, (void *) eraw_src, &internal_esym);
+
+      /* PR 17512: file: 3372-1000-0.004.  */
+      if (internal_esym.asym.iss >= ecoff_data (abfd)->debug_info.symbolic_header.issExtMax)
+       return FALSE;
+
       internal_ptr->symbol.name = (ecoff_data (abfd)->debug_info.ssext
                                   + internal_esym.asym.iss);
       if (!ecoff_set_symbol_info (abfd, &internal_esym.asym,
index c13fff335362a237ea2281746fd35fae1beea377..31ffa84966c2e015b824ed1fb649015b25be8514 100644 (file)
@@ -1349,8 +1349,12 @@ bfd_mach_o_canonicalize_one_reloc (bfd *abfd,
 
       if (reloc.r_extern)
        {
-         /* An external symbol number.  */
-         sym = syms + num;
+         /* PR 17512: file: 8396-1185-0.004.  */
+         if (num >= bfd_get_symcount (abfd))
+           sym = bfd_und_section_ptr->symbol_ptr_ptr;
+         else
+           /* An external symbol number.  */
+           sym = syms + num;
        }
       else if (num == 0x00ffffff || num == 0)
        {
@@ -2336,17 +2340,20 @@ bfd_mach_o_mangle_sections (bfd *abfd, bfd_mach_o_data_struct *mdata)
       && (mdata->nsects == 0 || mdata->sections != NULL))
     return TRUE;
 
+  /* We need to check that this can be done...  */
+  if (nsect > 255)
+    {
+      (*_bfd_error_handler) (_("mach-o: there are too many sections (%u)"
+                              " maximum is 255,\n"), nsect);
+      return FALSE;
+    }
+
   mdata->nsects = nsect;
   mdata->sections = bfd_alloc (abfd,
                               mdata->nsects * sizeof (bfd_mach_o_section *));
   if (mdata->sections == NULL)
     return FALSE;
 
-  /* We need to check that this can be done...  */
-  if (nsect > 255)
-    (*_bfd_error_handler) (_("mach-o: there are too many sections (%d)"
-                            " maximum is 255,\n"), nsect);
-
   /* Create Mach-O sections.
      Section type, attribute and align should have been set when the
      section was created - either read in or specified.  */
@@ -3646,6 +3653,9 @@ bfd_mach_o_read_symtab_strtab (bfd *abfd)
       if (bfd_seek (abfd, sym->stroff, SEEK_SET) != 0
           || bfd_bread (sym->strtab, sym->strsize, abfd) != sym->strsize)
         {
+         /* PR 17512: file: 10888-1609-0.004.  */
+         bfd_release (abfd, sym->strtab);
+         sym->strtab = NULL;
           bfd_set_error (bfd_error_file_truncated);
           return FALSE;
         }
@@ -3675,6 +3685,7 @@ bfd_mach_o_read_symtab_symbols (bfd *abfd)
 
   if (!bfd_mach_o_read_symtab_strtab (abfd))
     {
+      bfd_release (abfd, sym->symbols);
       sym->symbols = NULL;
       return FALSE;
     }
@@ -3683,6 +3694,7 @@ bfd_mach_o_read_symtab_symbols (bfd *abfd)
     {
       if (!bfd_mach_o_read_symtab_symbol (abfd, sym, &sym->symbols[i], i))
        {
+         bfd_release (abfd, sym->symbols);
          sym->symbols = NULL;
          return FALSE;
        }
index 57ec51fe19c52c40409f27c7626cc1fb1802c8a1..d7edc2b6837edf9eae69360054f978723ec7d663 100644 (file)
@@ -349,8 +349,11 @@ static reloc_howto_type howto_table[] =
 /* Customize coffcode.h.  */
 #define MIPS 1
 
-#define RTYPE2HOWTO(cache_ptr, dst) \
-           (cache_ptr)->howto = howto_table + (dst)->r_type;
+#define RTYPE2HOWTO(cache_ptr, dst)                            \
+  ((cache_ptr)->howto =                                                \
+   ((dst)->r_type < NUM_HOWTOS                                 \
+    ? howto_table + (dst)->r_type                              \
+    : NULL))
 
 /* Compute the addend of a reloc.  If the reloc is to a common symbol,
    the object file contains the value of the common symbol.  By the
index dc471734f616a42eac672b43425938dff8034160..dedfb6a4f984ef03fa05eae5bf82ce4dcca680d1 100644 (file)
@@ -7655,6 +7655,15 @@ bfd_generic_get_relocated_section_contents (bfd *abfd,
                     abfd, input_section, * parent);
                  goto error_return;
 
+               case bfd_reloc_notsupported:
+                 /* PR ld/17512
+                    This error can result when processing a corrupt binary.
+                    Do not abort.  Issue an error message instead.  */
+                 link_info->callbacks->einfo
+                   (_("%X%P: %B(%A): relocation \"%R\" is not supported\n"),
+                    abfd, input_section, * parent);
+                 goto error_return;
+
                default:
                  abort ();
                  break;
index 236899822c32ab85b497bb5785e96e979523ed47..1dfe7483778eed702507633e9a9b85ef8d2d64d7 100644 (file)
@@ -85,8 +85,8 @@ typedef struct versados_data_struct
 tdata_type;
 
 #define VDATA(abfd)       (abfd->tdata.versados_data)
-#define EDATA(abfd, n)    (abfd->tdata.versados_data->e[n])
-#define RDATA(abfd, n)    (abfd->tdata.versados_data->rest[n])
+#define EDATA(abfd, n)    (abfd->tdata.versados_data->e[(n) < 16 ? (n) : 0])
+#define RDATA(abfd, n)    (abfd->tdata.versados_data->rest[(n) < 240 ? (n) : 0])
 
 struct ext_otr
 {
@@ -181,14 +181,22 @@ versados_new_symbol (bfd *abfd,
   return n;
 }
 
-static int
+static bfd_boolean
 get_record (bfd *abfd, union ext_any *ptr)
 {
   if (bfd_bread (&ptr->size, (bfd_size_type) 1, abfd) != 1
       || (bfd_bread ((char *) ptr + 1, (bfd_size_type) ptr->size, abfd)
          != ptr->size))
-    return 0;
-  return 1;
+    return FALSE;
+
+  {
+    bfd_size_type amt = ptr->size + 1;
+
+    if (amt < sizeof (* ptr))
+      memset ((char *) ptr + amt, 0, sizeof (* ptr) - amt);
+  }
+
+  return TRUE;
 }
 
 static int
@@ -366,7 +374,7 @@ process_otr (bfd *abfd, struct ext_otr *otr, int pass)
 
   struct esdid *esdid = &EDATA (abfd, otr->esdid - 1);
   unsigned char *contents = esdid->contents;
-  int need_contents = 0;
+  bfd_boolean need_contents = FALSE;
   unsigned int dst_idx = esdid->pc;
 
   for (shift = ((unsigned long) 1 << 31); shift && srcp < endp; shift >>= 1)
@@ -390,8 +398,8 @@ process_otr (bfd *abfd, struct ext_otr *otr, int pass)
              int val = get_offset (offsetlen, srcp + esdids);
 
              if (pass == 1)
-               need_contents = 1;
-             else
+               need_contents = TRUE;
+             else if (contents)
                for (j = 0; j < sizeinwords * 2; j++)
                  {
                    contents[dst_idx + (sizeinwords * 2) - j - 1] = val;
@@ -429,19 +437,21 @@ process_otr (bfd *abfd, struct ext_otr *otr, int pass)
        }
       else
        {
-         need_contents = 1;
-         
-         if (esdid->section && dst_idx < esdid->section->size)
+         need_contents = TRUE;
+
+         if (esdid->section && contents && dst_idx < esdid->section->size)
            if (pass == 2)
              {
                /* Absolute code, comes in 16 bit lumps.  */
                contents[dst_idx] = srcp[0];
                contents[dst_idx + 1] = srcp[1];
              }
+
          dst_idx += 2;
          srcp += 2;
        }
     }
+
   EDATA (abfd, otr->esdid - 1).pc = dst_idx;
 
   if (!contents && need_contents)
@@ -461,7 +471,7 @@ process_otr (bfd *abfd, struct ext_otr *otr, int pass)
 static bfd_boolean
 versados_scan (bfd *abfd)
 {
-  int loop = 1;
+  bfd_boolean loop = TRUE;
   int i;
   int j;
   int nsecs = 0;
@@ -479,13 +489,13 @@ versados_scan (bfd *abfd)
       union ext_any any;
 
       if (!get_record (abfd, &any))
-       return TRUE;
+       return FALSE;
       switch (any.header.type)
        {
        case VHEADER:
          break;
        case VEND:
-         loop = 0;
+         loop = FALSE;
          break;
        case VESTDEF:
          process_esd (abfd, &any.esd, 1);
@@ -512,7 +522,6 @@ versados_scan (bfd *abfd)
        {
          amt = (bfd_size_type) esdid->relocs * sizeof (arelent);
          esdid->section->relocation = bfd_alloc (abfd, amt);
-
          esdid->pc = 0;
 
          if (esdid->contents)
@@ -571,7 +580,7 @@ versados_scan (bfd *abfd)
 
   VDATA (abfd)->ref_idx = 0;
 
-  return 1;
+  return TRUE;
 }
 
 /* Check whether an existing file is a versados  file.  */
@@ -773,6 +782,7 @@ versados_canonicalize_reloc (bfd *abfd,
 
   versados_pass_2 (abfd);
   src = section->relocation;
+
   if (!EDATA (abfd, section->target_index).donerel)
     {
       EDATA (abfd, section->target_index).donerel = 1;
@@ -790,6 +800,9 @@ versados_canonicalize_reloc (bfd *abfd,
 
              src[count].sym_ptr_ptr = e->section->symbol_ptr_ptr;
            }
+         /* PR 17512: file:3757-2936-0.004.  */
+         else if ((unsigned) (esdid - ES_BASE) >= bfd_get_symcount (abfd))
+           src[count].sym_ptr_ptr = bfd_und_section_ptr->symbol_ptr_ptr;
          else
            src[count].sym_ptr_ptr = symbols + esdid - ES_BASE;
        }
index 86c8555b5347a653bcb855aca9e0093b01edae43..542d7888735b15a786d67b6c3bf17d66d3cb3bee 100644 (file)
@@ -1,3 +1,16 @@
+2014-11-26  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17512
+       * dwarf.c (display_block): Do nothing if the block starts after
+       the end of the buffer.
+       (read_and_display_attr_value): Add range checks.
+       (struct Frame_Chunk): Make the ncols and ra fields unsigned.
+       (frame_need_space): Test for an ncols of zero.
+       (read_cie): Fail if the augmentation data extends off the end of
+       the buffer.
+       (display_debug_frames): Add checks for read_cie failing.  Add
+       range checks.
+
 2014-11-25  H.J. Lu  <hongjiu.lu@intel.com>
 
        * objdump.c (objdump_print_symname): Replace
index 8213f4dc9e106ad1ac11d16546f6510eb2944056..622fe913d419fe43a4d25ddf2ba28d921a8dfec4 100644 (file)
@@ -861,6 +861,8 @@ display_block (unsigned char *data,
   dwarf_vma maxlen;
 
   printf (_(" %s byte block: "), dwarf_vmatoa ("u", length));
+  if (data > end)
+    return (unsigned char *) end;
 
   maxlen = (dwarf_vma) (end - data);
   length = length > maxlen ? maxlen : length;
@@ -1654,6 +1656,12 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_FORM_exprloc:
       uvalue = read_uleb128 (data, & bytes_read, end);
       block_start = data + bytes_read;
+      if (block_start >= end)
+       {
+         warn (_("Block ends prematurely\n"));
+         uvalue = 0;
+         block_start = end;
+       }
       /* PR 17512: file: 008-103549-0.001:0.1.  */
       if (block_start + uvalue > end)
        {
@@ -1669,6 +1677,12 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_FORM_block1:
       SAFE_BYTE_GET (uvalue, data, 1, end);
       block_start = data + 1;
+      if (block_start >= end)
+       {
+         warn (_("Block ends prematurely\n"));
+         uvalue = 0;
+         block_start = end;
+       }
       if (block_start + uvalue > end)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
@@ -1683,6 +1697,12 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_FORM_block2:
       SAFE_BYTE_GET (uvalue, data, 2, end);
       block_start = data + 2;
+      if (block_start >= end)
+       {
+         warn (_("Block ends prematurely\n"));
+         uvalue = 0;
+         block_start = end;
+       }
       if (block_start + uvalue > end)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
@@ -1697,6 +1717,13 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_FORM_block4:
       SAFE_BYTE_GET (uvalue, data, 4, end);
       block_start = data + 4;
+      /* PR 17512: file: 3371-3907-0.004.  */
+      if (block_start >= end)
+       {
+         warn (_("Block ends prematurely\n"));
+         uvalue = 0;
+         block_start = end;
+       }
       if (block_start + uvalue > end)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
@@ -5080,7 +5107,7 @@ typedef struct Frame_Chunk
 {
   struct Frame_Chunk *next;
   unsigned char *chunk_start;
-  int ncols;
+  unsigned int ncols;
   /* DW_CFA_{undefined,same_value,offset,register,unreferenced}  */
   short int *col_type;
   int *col_offset;
@@ -5091,7 +5118,7 @@ typedef struct Frame_Chunk
   dwarf_vma pc_range;
   int cfa_reg;
   int cfa_offset;
-  int ra;
+  unsigned int ra;
   unsigned char fde_encoding;
   unsigned char cfa_exp;
   unsigned char ptr_size;
@@ -5106,13 +5133,13 @@ static unsigned int dwarf_regnames_count;
    in the frame info.  */
 #define DW_CFA_unreferenced (-1)
 
-/* Return 0 if not more space is needed, 1 if more space is needed,
+/* Return 0 if no more space is needed, 1 if more space is needed,
    -1 for invalid reg.  */
 
 static int
 frame_need_space (Frame_Chunk *fc, unsigned int reg)
 {
-  int prev = fc->ncols;
+  unsigned int prev = fc->ncols;
 
   if (reg < (unsigned int) fc->ncols)
     return 0;
@@ -5122,6 +5149,11 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg)
     return -1;
 
   fc->ncols = reg + 1;
+  /* PR 17512: file: 10450-2643-0.004.
+     If reg == -1 then this can happen...  */
+  if (fc->ncols == 0)
+    return -1;
+
   fc->col_type = (short int *) xcrealloc (fc->col_type, fc->ncols,
                                           sizeof (short int));
   fc->col_offset = (int *) xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
@@ -5280,9 +5312,9 @@ regname (unsigned int regno, int row)
 }
 
 static void
-frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs)
+frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_regs)
 {
-  int r;
+  unsigned int r;
   char tmp[100];
 
   if (*max_regs < fc->ncols)
@@ -5422,6 +5454,12 @@ read_cie (unsigned char *start, unsigned char *end,
       augmentation_data_len = LEB ();
       augmentation_data = start;
       start += augmentation_data_len;
+      /* PR 17512: file: 11042-2589-0.004.  */
+      if (start > end)
+       {
+         warn (_("Augmentation data too long: 0x%lx"), augmentation_data_len);
+         return end;
+       }
     }
 
   if (augmentation_data_len)
@@ -5430,7 +5468,7 @@ read_cie (unsigned char *start, unsigned char *end,
       p = (unsigned char *) fc->augmentation + 1;
       q = augmentation_data;
 
-      while (1)
+      while (p < end && q < augmentation_data + augmentation_data_len)
        {
          if (*p == 'L')
            q++;
@@ -5469,7 +5507,7 @@ display_debug_frames (struct dwarf_section *section,
   Frame_Chunk *rs;
   int is_eh = strcmp (section->name, ".eh_frame") == 0;
   unsigned int length_return;
-  int max_regs = 0;
+  unsigned int max_regs = 0;
   const char *bad_reg = _("bad register: ");
   int saved_eh_addr_size = eh_addr_size;
 
@@ -5534,18 +5572,19 @@ display_debug_frames (struct dwarf_section *section,
                                   || (offset_size == 8 && cie_id == DW64_CIE_ID)))
        {
          int version;
-         int mreg;
+         unsigned int mreg;
 
          start = read_cie (start, end, &cie, &version,
                            &augmentation_data_len, &augmentation_data);
          /* PR 17512: file: 027-135133-0.005.  */
          if (cie == NULL)
            break;
+
          fc = cie;
          fc->next = chunks;
          chunks = fc;
          fc->chunk_start = saved_start;
-         mreg = max_regs - 1;
+         mreg = max_regs > 0 ? max_regs - 1 : 0;
          if (mreg < fc->ra)
            mreg = fc->ra;
          frame_need_space (fc, mreg);
@@ -5578,8 +5617,11 @@ display_debug_frames (struct dwarf_section *section,
              if (augmentation_data_len)
                {
                  unsigned long i;
+
                  printf ("  Augmentation data:    ");
                  for (i = 0; i < augmentation_data_len; ++i)
+                   /* FIXME: If do_wide is FALSE, then we should
+                      add carriage returns at 80 columns...  */
                    printf (" %02x", augmentation_data[i]);
                  putchar ('\n');
                }
@@ -5635,14 +5677,20 @@ display_debug_frames (struct dwarf_section *section,
                             || (off_size == 8 && c_id == DW64_CIE_ID)))
                        {
                          int version;
-                         int mreg;
+                         unsigned int mreg;
 
                          read_cie (cie_scan, end, &cie, &version,
                                    &augmentation_data_len, &augmentation_data);
+                         /* PR 17512: file: 3450-2098-0.004.  */
+                         if (cie == NULL)
+                           {
+                             warn (_("Failed to read CIE information\n"));
+                             break;
+                           }
                          cie->next = forward_refs;
                          forward_refs = cie;
                          cie->chunk_start = look_for;
-                         mreg = max_regs - 1;
+                         mreg = max_regs > 0 ? max_regs - 1 : 0;
                          if (mreg < cie->ra)
                            mreg = cie->ra;
                          frame_need_space (cie, mreg);
@@ -5665,7 +5713,7 @@ display_debug_frames (struct dwarf_section *section,
              fc->ncols = 0;
              fc->col_type = (short int *) xmalloc (sizeof (short int));
              fc->col_offset = (int *) xmalloc (sizeof (int));
-             frame_need_space (fc, max_regs - 1);
+             frame_need_space (fc, max_regs > 0 ? max_regs - 1 : 0);
              cie = fc;
              fc->augmentation = "";
              fc->fde_encoding = 0;
@@ -5688,7 +5736,7 @@ display_debug_frames (struct dwarf_section *section,
              fc->cfa_reg = cie->cfa_reg;
              fc->cfa_offset = cie->cfa_offset;
              fc->ra = cie->ra;
-             frame_need_space (fc, max_regs - 1);
+             frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0);
              fc->fde_encoding = cie->fde_encoding;
            }
 
@@ -6167,10 +6215,9 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_def_cfa_expression:
              ul = LEB ();
-             if (start >= block_end)
+             if (start >= block_end || start + ul > block_end)
                {
-                 printf ("  DW_CFA_def_cfa_expression: <corrupt>\n");
-                 warn (_("Corrupt length field in DW_CFA_def_cfa_expression\n"));
+                 printf (_("  DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul);
                  break;
                }
              if (! do_debug_frames_interp)
@@ -6190,10 +6237,9 @@ display_debug_frames (struct dwarf_section *section,
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              /* PR 17512: file: 069-133014-0.006.  */
-             if (start >= block_end)
+             if (start >= block_end || start + ul > block_end)
                {
-                 printf ("  DW_CFA_expression: <corrupt>\n");
-                 warn (_("Corrupt length field in DW_CFA_expression\n"));
+                 printf (_("  DW_CFA_expression: <corrupt len %lu>\n"), ul);
                  break;
                }
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -6214,10 +6260,9 @@ display_debug_frames (struct dwarf_section *section,
              ul = LEB ();
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
-             if (start >= block_end)
+             if (start >= block_end || start + ul > block_end)
                {
-                 printf ("  DW_CFA_val_expression: <corrupt>\n");
-                 warn (_("Corrupt length field in DW_CFA_val_expression\n"));
+                 printf ("  DW_CFA_val_expression: <corrupt len %lu>\n", ul);
                  break;
                }
              if (! do_debug_frames_interp || *reg_prefix != '\0')