From: Nick Clifton Date: Wed, 26 Nov 2014 14:11:23 +0000 (+0000) Subject: More fixes for memory access errors triggered by attemps to examine corrupted binaries. X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=a11652892c18324bf3abb8b25c01475e5a18632a;p=deliverable%2Fbinutils-gdb.git More fixes for memory access errors triggered by attemps to examine corrupted binaries. 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. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index d188bd7cef..c379fcae2b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,43 @@ +2014-11-26 Nick Clifton + + 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 * elf.c (_bfd_elf_slurp_version_tables): Delay allocation of diff --git a/bfd/coff-h8300.c b/bfd/coff-h8300.c index 5ec48c960d..10123d3e52 100644 --- a/bfd/coff-h8300.c +++ b/bfd/coff-h8300.c @@ -337,7 +337,7 @@ rtype2howto (arelent *internal, struct internal_reloc *dst) internal->howto = howto_table + 19; break; default: - abort (); + internal->howto = NULL; break; } } diff --git a/bfd/coff-h8500.c b/bfd/coff-h8500.c index 574f95648b..b6a996e943 100644 --- a/bfd/coff-h8500.c +++ b/bfd/coff-h8500.c @@ -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; diff --git a/bfd/coff-ia64.c b/bfd/coff-ia64.c index 38a0a381f1..f1641dbbda 100644 --- a/bfd/coff-ia64.c +++ b/bfd/coff-ia64.c @@ -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 diff --git a/bfd/coff-m68k.c b/bfd/coff-m68k.c index f7089a681b..5ebf52c3c9 100644 --- a/bfd/coff-m68k.c +++ b/bfd/coff-m68k.c @@ -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; } } diff --git a/bfd/coff-mcore.c b/bfd/coff-mcore.c index 7dad44fdce..9f30cfcb62 100644 --- a/bfd/coff-mcore.c +++ b/bfd/coff-mcore.c @@ -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; diff --git a/bfd/coff-tic30.c b/bfd/coff-tic30.c index 740c82c867..ab953088c7 100644 --- a/bfd/coff-tic30.c +++ b/bfd/coff-tic30.c @@ -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; } } diff --git a/bfd/coff-w65.c b/bfd/coff-w65.c index f2087308aa..483ae8048b 100644 --- a/bfd/coff-w65.c +++ b/bfd/coff-w65.c @@ -31,16 +31,18 @@ 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) diff --git a/bfd/coff-we32k.c b/bfd/coff-we32k.c index d5481b8ff2..b754815e70 100644 --- a/bfd/coff-we32k.c +++ b/bfd/coff-we32k.c @@ -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 diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c index 2a21bb8be6..742adc29e0 100644 --- a/bfd/coff-x86_64.c +++ b/bfd/coff-x86_64.c @@ -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; } } diff --git a/bfd/coff-z80.c b/bfd/coff-z80.c index 7b62cdf149..fd68b12434 100644 --- a/bfd/coff-z80.c +++ b/bfd/coff-z80.c @@ -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; diff --git a/bfd/coff-z8k.c b/bfd/coff-z8k.c index c85713ff8d..7f67ee8f5b 100644 --- a/bfd/coff-z8k.c +++ b/bfd/coff-z8k.c @@ -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; diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 9990b169ec..1719b2d900 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -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) diff --git a/bfd/coffgen.c b/bfd/coffgen.c index 4f3f86219c..2b8884d3ad 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -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); } diff --git a/bfd/ecoff.c b/bfd/ecoff.c index 01f51e644e..33e213491a 100644 --- a/bfd/ecoff.c +++ b/bfd/ecoff.c @@ -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, diff --git a/bfd/mach-o.c b/bfd/mach-o.c index c13fff3353..31ffa84966 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -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; } diff --git a/bfd/pe-mips.c b/bfd/pe-mips.c index 57ec51fe19..d7edc2b683 100644 --- a/bfd/pe-mips.c +++ b/bfd/pe-mips.c @@ -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 diff --git a/bfd/reloc.c b/bfd/reloc.c index dc471734f6..dedfb6a4f9 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -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; diff --git a/bfd/versados.c b/bfd/versados.c index 236899822c..1dfe748377 100644 --- a/bfd/versados.c +++ b/bfd/versados.c @@ -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; } diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 86c8555b53..542d788873 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,16 @@ +2014-11-26 Nick Clifton + + 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 * objdump.c (objdump_print_symname): Replace diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 8213f4dc9e..622fe913d4 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -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: \n"); - warn (_("Corrupt length field in DW_CFA_def_cfa_expression\n")); + printf (_(" DW_CFA_def_cfa_expression: \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: \n"); - warn (_("Corrupt length field in DW_CFA_expression\n")); + printf (_(" DW_CFA_expression: \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: \n"); - warn (_("Corrupt length field in DW_CFA_val_expression\n")); + printf (" DW_CFA_val_expression: \n", ul); break; } if (! do_debug_frames_interp || *reg_prefix != '\0')