diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 282 | ||||
-rw-r--r-- | bfd/aoutx.h | 24 | ||||
-rw-r--r-- | bfd/archive.c | 5 | ||||
-rw-r--r-- | bfd/coff-i386.c | 17 | ||||
-rw-r--r-- | bfd/coff-x86_64.c | 11 | ||||
-rw-r--r-- | bfd/coffcode.h | 170 | ||||
-rw-r--r-- | bfd/coffgen.c | 168 | ||||
-rw-r--r-- | bfd/cofflink.c | 5 | ||||
-rw-r--r-- | bfd/elf.c | 24 | ||||
-rw-r--r-- | bfd/ieee.c | 6 | ||||
-rw-r--r-- | bfd/libcoff-in.h | 3 | ||||
-rw-r--r-- | bfd/libcoff.h | 16 | ||||
-rw-r--r-- | bfd/opncls.c | 41 | ||||
-rw-r--r-- | bfd/pe-mips.c | 9 | ||||
-rw-r--r-- | bfd/peXXigen.c | 220 | ||||
-rw-r--r-- | bfd/peicode.h | 15 | ||||
-rw-r--r-- | bfd/tekhex.c | 112 | ||||
-rw-r--r-- | bfd/xcofflink.c | 5 |
18 files changed, 855 insertions, 278 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c7aef87f534..7c07de94b9e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,285 @@ +2014-11-17 Nick Clifton <nickc@redhat.com> + + Apply trunk patches: + + 2014-11-14 Nick Clifton <nickc@redhat.com> + + PR binutils/17597 + * opncls.c (bfd_get_debug_link_info): Avoid reading off the end of + the section. + (bfd_get_alt_debug_link_info): Likewise. + + 2014-11-14 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * ieee.c (ieee_archive_p) Skip processing if no bytes are read at + all. + (ieee_object_p): Likewise. + + 2014-11-13 H.J. Lu <hongjiu.lu@intel.com> + + * coffcode.h (coff_slurp_line_table): Add cast to unsigned int. + + 2014-11-13 H.J. Lu <hongjiu.lu@intel.com> + + * coffcode.h (coff_pointerize_aux_hook): Fix a typo. + + 2014-11-13 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * coffcode.h (coff_ptr_struct): Add is_sym field. + (coff_new_section_hook): Set the is_sym field. + (coff_pointerize_aux_hook): Check the is_sym field. + (coff_print_aux): Likewise. + (coff_compute_section_file_positions): Likewise. + (coff_write_object_contents): Likewise. + (coff_slurp_line_table): Likewise. + (coff_slurp_symbol_table): Likewise. + (CALC_ADDEND): Likewise. + * coffgen.c (coff_renumber_symbols): Likewise. + (coff_mangle_symbols): Likewise. + (coff_fix_symbol_name): Likewise. + (coff_write_symbol): Likewise. + (coff_write_alien_symbol): Likewise. + (coff_write_native_symbol): Likewise. + (coff_write_symbols): Likewise. + (coff_write_linenumbers): Likewise. + (coff_pointerize_aux): Likewise. + (coff_get_normalized_symtab): Likewise. + (coff_get_symbol_info): Likewise. + (bfd_coff_get_syment): Likewise. + (bfd_coff_get_auxent): Likewise. + (coff_print_symbol): Likewise. + (coff_find_nearest_line_with_names): Likewise. + (bfd_coff_set_symbol_class): Likewise. + (coff_make_empty_symbol): Set the is_sym field. + (coff_bfd_make_debug_symbol): Likewise. + * peicode.h (pe_ILF_make_a_symbol): Likewise. + * libcoff.h: Regenerate. + * libcoff-in.h: Regenerate. + + 2014-11-12 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * coffcode.h (coff_slurp_line_table): Set the line number of + corrupt entries to -1. + (coff_slurp_symbol_table): Alway initialise the value of the + symbol. + * coffgen.c (coff_print_symbol): Check that the combined pointer + is valid. + (coff_print_symbol): Do not print negative line numbers. + * peXXigen.c (pe_print_idata): Add range checking displaying + member names. + + 2014-11-12 Alan Modra <amodra@gmail.com> + + PR binutils/17512 + * coffcode.h (coff_slurp_line_table): Drop line number info + not preceded by a valid function entry. Revert last change. + + 2014-11-11 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * coffcode.h (coff_slurp_line_table): Initialise the parts of the + line number cache that would not be initialised by the copy from + the new line number table. + (coff_classify_symbol): Allow for _bfd_coff_internal_syment_name + returning NULL. + * coffgen.c (coff_get_normalized_symbols): Get the external + symbols before allocating space for the internal symbols, in case + the get fails. + * elf.c (_bfd_elf_slurp_version_tables): Only allocate a verref + array if one is needed. Likewise with the verdef array. + * peXXigen.c (_bfd_XXi_swap_sym_in): Replace abort()'s with error + messages. + (_bfd_XXi_swap_aux_in): Make sure that all fields of the aux + structure are initialised. + (pe_print_edata): Avoid reading off the end of the data buffer. + + 2014-11-11 Alan Modra <amodra@gmail.com> + + PR binutils/17512 + * coffcode.h (coff_slurp_line_table): Use updated lineno_count + when building func_table. + + 2014-11-11 Alan Modra <amodra@gmail.com> + + PR binutils/17512 + * coffcode.h (coff_slurp_line_table): Don't bfd_zalloc, just + memset the particular bits we need. Update src after hitting loop + "continue". Don't count lineno omitted due to invalid symbols in + nbr_func, and update lineno_count. Init entire terminating + lineno. Don't both allocating terminator in n_lineno_cache. + Redirect sym->lineno pointer to where n_lineno_cache will be + copied, and free n_lineno_cache. + * pe-mips.c (NUM_HOWTOS): Typo fix. + + 2014-11-10 Nick Clifton <nickc@redhat.com> + + PR binutils/17521 + * coff-i386.c (NUM_HOWTOS): New define. + (RTYPE2HOWTO): Use it. + (coff_i386_rtype_to_howto): Likewise. + (coff_i386_reloc_name_lookup): Likewise. + (CALC_ADDEND): Check that reloc r_type field is valid. + * coff-x86_64.c (NUM_HOWTOS): New define. + (RTYPE2HOWTO): Use it. + (coff_amd64_rtype_to_howto): Likewise. + (coff_amd64_reloc_name_lookup): Likewise. + (CALC_ADDEND): Check that reloc r_type field is valid. + * coffcode.h (coff_slurp_line_table): Check for symbol table + indexing underflow. + (coff_slurp_symbol_table): Use zalloc to ensure that all table + entries are initialised. + * coffgen.c (_bfd_coff_read_string_table): Initialise unused bits + in the string table. Also ensure that the table is 0 terminated. + (coff_get_normalized_symtab): Check for symbol table indexing + underflow. + * opncls.c (bfd_alloc): Catch the case where a small negative size + can result in only 1 byte being allocated. + (bfd_alloc2): Use bfd_alloc. + * pe-mips.c (NUM_HOWTOS): New define. + (coff_mips_reloc_name_lookup): Use it. + (CALC_ADDEND): Check that reloc r_type field is valid. + * peXXigen.c (_bfd_XXi_swap_aouthdr_in): Initialise unused entries + in the DataDirectory. + (pe_print_idata): Avoid reading beyond the end of the data block + wen printing strings. + (pe_print_edata): Likewise. + Check for table indexing underflow. + * peicode.h (pe_mkobject): Initialise the pe_opthdr field. + (pe_bfd_object_p): Allocate and initialize enough space to hold a + PEAOUTHDR, even if the opt_hdr field specified less. + + 2014-11-08 Alan Modra <amodra@gmail.com> + + * peXXigen.c (pe_print_idata): Revert last patch, cast lhs instead. + + 2014-11-07 H.J. Lu <hongjiu.lu@intel.com> + + * peXXigen.c (pe_print_idata): Cast to unsigned long in range + checks. + + 2014-11-07 Alan Modra <amodra@gmail.com> + + * tekhex.c (tekhex_set_arch_mach): Ignore unknown arch errors. + + 2014-11-07 Alan Modra <amodra@gmail.com> + + * tekhex.c (CHUNK_SPAN): Define. + (struct data_struct <chunk_init>): Use one byte per span, update + all code accessing this field. + (find_chunk): Add create param, don't create new entry unless set. + (insert_byte): Don't save zeros. + (first_phase): Set section SEC_CODE or SEC_DATA flag depending + on symbol type. Create an alternate section if both types of + symbol are given. Attach type '2' and '6' symbols to absolute + section. + (move_section_contents): Fix caching of chunk. Don't create chunk + when reading, or for writing zeros. + (tekhex_set_section_contents): Don't create initial chunks. + (tekhex_write_object_contents): Use CHUNK_SPAN. + + 2014-11-07 Alan Modra <amodra@gmail.com> + + * aoutx.h (aout_get_external_symbols): Tidy allocation of symbol buffer. + + 2014-11-07 Alan Modra <amodra@gmail.com> + + * archive.c (_bfd_slurp_extended_name_table): Revert bfd_get_size check. + * coffcode.h (coff_set_alignment_hook): Likewise. + (coff_slurp_line_table): Likewise. + * coffgen.c (coff_get_normalized_symtab): Likewise. + (_bfd_coff_get_external_symbols): Likewise. + * elf.c (bfd_elf_get_str_section): Likewise. + * tekhex.c (first_phase): Likewise. + + 2014-11-06 Nick Clifton <nickc@redhat.com> + + * aoutx.h (slurp_symbol_table): Revert previous delta. + (slurp_reloc_table): Likewise. + * compress.c (bfd_get_full_section_contents): Remove file size + test. + * coffgen.c (coff_get_normalized_symtab): Allow zero-sized symtabs + and do not complain about linker generated files. + + 2014-11-04 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * coffcode.h (handle_COMDAT): Replace abort with BFD_ASSERT. + Replace another abort with an error message. + (coff_slurp_line_table): Add more range checking. + * peXXigen.c (pe_print_debugdata): Add range checking. + + 2014-11-05 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * coffcode.h (coff_set_alignment_hook): Warn if the file lies + about the number of relocations it contains. + (coff_sort_func_alent): Return 0 if the pointers are NULL. + (coff_slurp_line_table): Add more range checks. Do not free new + tables created when sorting line numbers. + * peXXigen.c (pe_print_idata): Add range checks. + (pe_print_edata): Likewise. + (rsrc_print_resource_entries): Likewise. Avoid printing control + characters. Terminate priniting if corruption is detected. + (rsrc_print_resource_directory): Terminate printing if an unknown + directory type is encountered. + (pe_print_debugdata): Fix off-by-one error. + (rsrc_count_entries): Add range checking. + (rsrc_parse_entry): Likewise. + + 2014-11-04 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * compress.c (bfd_get_full_section_contents): Improve test for + linker created objects. + + PR binutils/17533 + * archive.c (_bfd_slurp_extended_name_table): Handle archives with + corrupt extended name tables. + + 2014-11-03 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * aoutx.h (slurp_symbol_table): Check that computed table size is + not bigger than the file from which is it being read. + (slurp_reloc_table): Likewise. + * coffcode.h (coff_slurp_line_table): Remove unneeded local + 'warned'. Do not try to print the details of a symbol with an + invalid index. + * coffgen.c (make_a_sectiobn_from_file): Check computed string + index against length of string table. + (bfd_coff_internal_syment_name): Check read in string offset + against length of string table. + (build_debug_section): Return a pointer to the section used. + (_bfd_coff_read_string_table): Store the length of the string + table in the coff_tdata structure. + (bfd_coff_free_symbols): Set the length of the string table to + zero when it is freed. + (coff_get_normalized_symtab): Check offsets against string table + or data table lengths as appropriate. + * cofflink.c (_bfd_coff_link_input_bfd): Check offset against + length of string table. + * compress.c (bfd_get_full_section_contents): Check computed size + against the size of the file. + * libcoff-in.h (obj_coff_strings_len): Define. + (struct coff_tdata): Add strings_len field. + * libcoff.h: Regenerate. + * peXXigen.c (pe_print_debugdata): Do not attempt to print the + data if the debug section is too small. + * xcofflink.c (xcoff_link_input_bfd): Check offset against + length of string table. + + 2014-10-31 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * coffgen.c (_bfd_coff_get_external_symbols): Do not try to load a + symbol table bigger than the file. + * elf.c (bfd_elf_get_str_section): Do not try to load a string + table bigger than the file. + * tekhex.c (first_phase): Check that the section range is sane. + 2014-11-11 Alan Modra <amodra@gmail.com> * elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Adjust section diff --git a/bfd/aoutx.h b/bfd/aoutx.h index bef59b42366..9385a98570d 100644 --- a/bfd/aoutx.h +++ b/bfd/aoutx.h @@ -1300,14 +1300,14 @@ aout_get_external_symbols (bfd *abfd) { bfd_size_type count; struct external_nlist *syms; + bfd_size_type amt = exec_hdr (abfd)->a_syms; - count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE; + count = amt / EXTERNAL_NLIST_SIZE; if (count == 0) return TRUE; /* Nothing to do. */ #ifdef USE_MMAP - if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd), - exec_hdr (abfd)->a_syms, + if (! bfd_get_file_window (abfd, obj_sym_filepos (abfd), amt, &obj_aout_sym_window (abfd), TRUE)) return FALSE; syms = (struct external_nlist *) obj_aout_sym_window (abfd).data; @@ -1315,20 +1315,16 @@ aout_get_external_symbols (bfd *abfd) /* We allocate using malloc to make the values easy to free later on. If we put them on the objalloc it might not be possible to free them. */ - syms = (struct external_nlist *) bfd_malloc (count * EXTERNAL_NLIST_SIZE); + syms = (struct external_nlist *) bfd_malloc (amt); if (syms == NULL) return FALSE; - { - bfd_size_type amt; - amt = exec_hdr (abfd)->a_syms; - if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 - || bfd_bread (syms, amt, abfd) != amt) - { - free (syms); - return FALSE; - } - } + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 + || bfd_bread (syms, amt, abfd) != amt) + { + free (syms); + return FALSE; + } #endif obj_aout_external_syms (abfd) = syms; diff --git a/bfd/archive.c b/bfd/archive.c index 40a3395ba09..df37996d74b 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1300,6 +1300,8 @@ _bfd_slurp_extended_name_table (bfd *abfd) { byebye: free (namedata); + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->extended_names_size = 0; return FALSE; } @@ -1316,11 +1318,12 @@ _bfd_slurp_extended_name_table (bfd *abfd) text, the entries in the list are newline-padded, not null padded. In SVR4-style archives, the names also have a trailing '/'. DOS/NT created archive often have \ in them - We'll fix all problems here.. */ + We'll fix all problems here. */ { char *ext_names = bfd_ardata (abfd)->extended_names; char *temp = ext_names; char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) { if (*temp == ARFMAG[1]) diff --git a/bfd/coff-i386.c b/bfd/coff-i386.c index 87b014b9174..848d69b91c0 100644 --- a/bfd/coff-i386.c +++ b/bfd/coff-i386.c @@ -340,16 +340,18 @@ static reloc_howto_type howto_table[] = PCRELOFFSET) /* pcrel_offset */ }; +#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) I386BADMAG(x) #define I386 1 /* Customize coffcode.h */ -#define RTYPE2HOWTO(cache_ptr, dst) \ - ((cache_ptr)->howto = \ - ((dst)->r_type < sizeof (howto_table) / sizeof (howto_table[0]) \ - ? howto_table + (dst)->r_type \ +#define RTYPE2HOWTO(cache_ptr, dst) \ + ((cache_ptr)->howto = \ + ((dst)->r_type < NUM_HOWTOS \ + ? howto_table + (dst)->r_type \ : NULL)) /* For 386 COFF a STYP_NOLOAD | STYP_BSS section is part of a shared @@ -386,7 +388,8 @@ static reloc_howto_type howto_table[] = cache_ptr->addend = - (ptr->section->vma + ptr->value); \ else \ cache_ptr->addend = 0; \ - if (ptr && howto_table[reloc.r_type].pc_relative) \ + if (ptr && reloc.r_type < NUM_HOWTOS \ + && howto_table[reloc.r_type].pc_relative) \ cache_ptr->addend += asect->vma; \ } @@ -438,7 +441,7 @@ coff_i386_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, { reloc_howto_type *howto; - if (rel->r_type >= sizeof (howto_table) / sizeof (howto_table[0])) + if (rel->r_type >= NUM_HOWTOS) { bfd_set_error (bfd_error_bad_value); return NULL; @@ -574,7 +577,7 @@ coff_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, { unsigned int i; - for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) + for (i = 0; i < NUM_HOWTOS; i++) if (howto_table[i].name != NULL && strcasecmp (howto_table[i].name, r_name) == 0) return &howto_table[i]; diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c index 8d237338bf7..2a21bb8be69 100644 --- a/bfd/coff-x86_64.c +++ b/bfd/coff-x86_64.c @@ -448,6 +448,8 @@ static reloc_howto_type howto_table[] = PCRELOFFSET) /* pcrel_offset */ }; +#define NUM_HOWTOS ARRAY_SIZE (howto_table) + /* Turn a howto into a reloc nunmber */ #define SELECT_RELOC(x,howto) { x.r_type = howto->type; } @@ -456,7 +458,7 @@ static reloc_howto_type howto_table[] = #define RTYPE2HOWTO(cache_ptr, dst) \ ((cache_ptr)->howto = \ - ((dst)->r_type < ARRAY_SIZE (howto_table)) \ + ((dst)->r_type < NUM_HOWTOS) \ ? howto_table + (dst)->r_type \ : NULL) @@ -496,7 +498,8 @@ static reloc_howto_type howto_table[] = cache_ptr->addend = - (ptr->section->vma + ptr->value); \ else \ cache_ptr->addend = 0; \ - if (ptr && howto_table[reloc.r_type].pc_relative) \ + if (ptr && reloc.r_type < NUM_HOWTOS \ + && howto_table[reloc.r_type].pc_relative) \ cache_ptr->addend += asect->vma; \ } @@ -546,7 +549,7 @@ coff_amd64_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED, { reloc_howto_type *howto; - if (rel->r_type >= ARRAY_SIZE (howto_table)) + if (rel->r_type >= NUM_HOWTOS) { bfd_set_error (bfd_error_bad_value); return NULL; @@ -689,7 +692,7 @@ coff_amd64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, { unsigned int i; - for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++) + for (i = 0; i < NUM_HOWTOS; i++) if (howto_table[i].name != NULL && strcasecmp (howto_table[i].name, r_name) == 0) return &howto_table[i]; diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 6678b88bbd5..9990b169ecc 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -307,7 +307,7 @@ CODE_FRAGMENT .typedef struct coff_ptr_struct .{ . {* Remembers the offset from the first symbol in the file for -. this symbol. Generated by coff_renumber_symbols. *} +. this symbol. Generated by coff_renumber_symbols. *} . unsigned int offset; . . {* Should the value of this symbol be renumbered. Used for @@ -315,15 +315,15 @@ CODE_FRAGMENT . unsigned int fix_value : 1; . . {* Should the tag field of this symbol be renumbered. -. Created by coff_pointerize_aux. *} +. Created by coff_pointerize_aux. *} . unsigned int fix_tag : 1; . . {* Should the endidx field of this symbol be renumbered. -. Created by coff_pointerize_aux. *} +. Created by coff_pointerize_aux. *} . unsigned int fix_end : 1; . . {* Should the x_csect.x_scnlen field be renumbered. -. Created by coff_pointerize_aux. *} +. Created by coff_pointerize_aux. *} . unsigned int fix_scnlen : 1; . . {* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the @@ -331,12 +331,15 @@ CODE_FRAGMENT . unsigned int fix_line : 1; . . {* The container for the symbol structure as read and translated -. from the file. *} +. from the file. *} . union . { . union internal_auxent auxent; . struct internal_syment syment; . } u; +. +. {* Selector for the union above. *} +. bfd_boolean is_sym; .} combined_entry_type; . . @@ -928,12 +931,7 @@ handle_COMDAT (bfd * abfd, bfd_coff_swap_sym_in (abfd, esym, & isym); - if (sizeof (internal_s->s_name) > SYMNMLEN) - { - /* This case implies that the matching - symbol name will be in the string table. */ - abort (); - } + BFD_ASSERT (sizeof (internal_s->s_name) <= SYMNMLEN); if (isym.n_scnum == section->target_index) { @@ -964,8 +962,12 @@ handle_COMDAT (bfd * abfd, /* All 3 branches use this. */ symname = _bfd_coff_internal_syment_name (abfd, &isym, buf); + /* PR 17512 file: 078-11867-0.004 */ if (symname == NULL) - abort (); + { + _bfd_error_handler (_("%B: unable to load COMDAT section name"), abfd); + break; + } switch (seen_state) { @@ -1797,6 +1799,7 @@ coff_new_section_hook (bfd * abfd, asection * section) in case this symbol winds up getting written out. The value 0 for n_numaux is already correct. */ + native->is_sym = TRUE; native->u.syment.n_type = T_NULL; native->u.syment.n_sclass = sclass; @@ -2498,11 +2501,13 @@ coff_pointerize_aux_hook (bfd *abfd ATTRIBUTE_UNUSED, unsigned int indaux, combined_entry_type *aux) { + BFD_ASSERT (symbol->is_sym); int n_sclass = symbol->u.syment.n_sclass; if (CSECT_SYM_P (n_sclass) && indaux + 1 == symbol->u.syment.n_numaux) { + BFD_ASSERT (! aux->is_sym); if (SMTYP_SMTYP (aux->u.auxent.x_csect.x_smtyp) == XTY_LD) { aux->u.auxent.x_csect.x_scnlen.p = @@ -2535,6 +2540,7 @@ coff_pointerize_aux_hook (bfd *abfd ATTRIBUTE_UNUSED, /* Return TRUE if we don't want to pointerize this aux entry, which is the case for the lastfirst aux entry for a C_LEAFPROC symbol. */ return (indaux == 1 + && symbol->is_sym && (symbol->u.syment.n_sclass == C_LEAFPROC || symbol->u.syment.n_sclass == C_LEAFSTAT || symbol->u.syment.n_sclass == C_LEAFEXT)); @@ -2557,6 +2563,8 @@ coff_print_aux (bfd *abfd ATTRIBUTE_UNUSED, combined_entry_type *aux ATTRIBUTE_UNUSED, unsigned int indaux ATTRIBUTE_UNUSED) { + BFD_ASSERT (symbol->is_sym); + BFD_ASSERT (! aux->is_sym); #ifdef RS6000COFF_C if (CSECT_SYM_P (symbol->u.syment.n_sclass) && indaux + 1 == symbol->u.syment.n_numaux) @@ -3169,6 +3177,7 @@ coff_compute_section_file_positions (bfd * abfd) cf = coff_symbol_from (abfd, *symp); if (cf != NULL && cf->native != NULL + && cf->native->is_sym && SYMNAME_IN_DEBUG (&cf->native->u.syment)) { size_t len; @@ -3866,6 +3875,7 @@ coff_write_object_contents (bfd * abfd) csym = coff_symbol_from (abfd, *psym); if (csym == NULL || csym->native == NULL + || ! csym->native->is_sym || csym->native->u.syment.n_numaux < 1 || csym->native->u.syment.n_sclass != C_STAT || csym->native->u.syment.n_type != T_NULL) @@ -3888,6 +3898,7 @@ coff_write_object_contents (bfd * abfd) x_associated field is not currently supported. */ aux = csym->native + 1; + BFD_ASSERT (! aux->is_sym); switch (current->flags & SEC_LINK_DUPLICATES) { case SEC_LINK_DUPLICATES_DISCARD: @@ -4033,8 +4044,6 @@ coff_write_object_contents (bfd * abfd) internal_f.f_flags |= F_DYNLOAD; #endif - memset (&internal_a, 0, sizeof internal_a); - /* Set up architecture-dependent stuff. */ { unsigned int magic = 0; @@ -4456,11 +4465,11 @@ buy_and_read (bfd *abfd, file_ptr where, bfd_size_type size) void * area = bfd_alloc (abfd, size); if (!area) - return (NULL); + return NULL; if (bfd_seek (abfd, where, SEEK_SET) != 0 || bfd_bread (area, size, abfd) != size) - return (NULL); - return (area); + return NULL; + return area; } /* @@ -4494,6 +4503,8 @@ coff_sort_func_alent (const void * arg1, const void * arg2) const coff_symbol_type *s1 = (const coff_symbol_type *) (al1->u.sym); const coff_symbol_type *s2 = (const coff_symbol_type *) (al2->u.sym); + if (s1 == NULL || s2 == NULL) + return 0; if (s1->symbol.value < s2->symbol.value) return -1; else if (s1->symbol.value > s2->symbol.value) @@ -4511,9 +4522,10 @@ coff_slurp_line_table (bfd *abfd, asection *asect) unsigned int counter; alent *cache_ptr; bfd_vma prev_offset = 0; - int ordered = 1; + bfd_boolean ordered = TRUE; unsigned int nbr_func; LINENO *src; + bfd_boolean have_func; BFD_ASSERT (asect->lineno == NULL); @@ -4536,57 +4548,85 @@ coff_slurp_line_table (bfd *abfd, asection *asect) asect->lineno = lineno_cache; src = native_lineno; nbr_func = 0; + have_func = FALSE; - for (counter = 0; counter < asect->lineno_count; counter++) + for (counter = 0; counter < asect->lineno_count; counter++, src++) { struct internal_lineno dst; bfd_coff_swap_lineno_in (abfd, src, &dst); cache_ptr->line_number = dst.l_lnno; + /* Appease memory checkers that get all excited about + uninitialised memory when copying alents if u.offset is + larger than u.sym. (64-bit BFD on 32-bit host.) */ + memset (&cache_ptr->u, 0, sizeof (cache_ptr->u)); if (cache_ptr->line_number == 0) { - bfd_boolean warned; - bfd_signed_vma symndx; + combined_entry_type * ent; + bfd_vma symndx; coff_symbol_type *sym; - nbr_func++; - warned = FALSE; + have_func = FALSE; symndx = dst.l_addr.l_symndx; - if (symndx < 0 - || (bfd_vma) symndx >= obj_raw_syment_count (abfd)) + if (symndx >= obj_raw_syment_count (abfd)) { (*_bfd_error_handler) - (_("%B: warning: illegal symbol index %ld in line numbers"), - abfd, (long) symndx); - symndx = 0; - warned = TRUE; + (_("%B: warning: illegal symbol index 0x%lx in line number entry %d"), + abfd, (long) symndx, counter); + cache_ptr->line_number = -1; + continue; } + ent = obj_raw_syments (abfd) + symndx; /* FIXME: We should not be casting between ints and pointers like this. */ - sym = ((coff_symbol_type *) - ((symndx + obj_raw_syments (abfd)) - ->u.syment._n._n_n._n_zeroes)); + if (! ent->is_sym) + { + (*_bfd_error_handler) + (_("%B: warning: illegal symbol index 0x%lx in line number entry %d"), + abfd, (long) symndx, counter); + cache_ptr->line_number = -1; + continue; + } + sym = (coff_symbol_type *) (ent->u.syment._n._n_n._n_zeroes); + + /* PR 17512 file: 078-10659-0.004 */ + if (sym < obj_symbols (abfd) + || sym >= obj_symbols (abfd) + bfd_get_symcount (abfd)) + { + (*_bfd_error_handler) + (_("%B: warning: illegal symbol in line number entry %d"), + abfd, counter); + cache_ptr->line_number = -1; + continue; + } + + have_func = TRUE; + nbr_func++; cache_ptr->u.sym = (asymbol *) sym; - if (sym->lineno != NULL && ! warned) + if (sym->lineno != NULL) (*_bfd_error_handler) (_("%B: warning: duplicate line number information for `%s'"), abfd, bfd_asymbol_name (&sym->symbol)); sym->lineno = cache_ptr; if (sym->symbol.value < prev_offset) - ordered = 0; + ordered = FALSE; prev_offset = sym->symbol.value; } + else if (!have_func) + /* Drop line information that has no associated function. + PR 17521: file: 078-10659-0.004. */ + continue; else - cache_ptr->u.offset = dst.l_addr.l_paddr - - bfd_section_vma (abfd, asect); - + cache_ptr->u.offset = (dst.l_addr.l_paddr + - bfd_section_vma (abfd, asect)); cache_ptr++; - src++; } - cache_ptr->line_number = 0; + + asect->lineno_count = cache_ptr - lineno_cache; + memset (cache_ptr, 0, sizeof (*cache_ptr)); bfd_release (abfd, native_lineno); /* On some systems (eg AIX5.3) the lineno table may not be sorted. */ @@ -4603,15 +4643,17 @@ coff_slurp_line_table (bfd *abfd, asection *asect) alent **p = func_table; unsigned int i; - for (i = 0; i < counter; i++) + for (i = 0; i < asect->lineno_count; i++) if (lineno_cache[i].line_number == 0) *p++ = &lineno_cache[i]; + BFD_ASSERT ((unsigned int) (p - func_table) == nbr_func); + /* Sort by functions. */ qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent); /* Create the new sorted table. */ - amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent); + amt = (bfd_size_type) asect->lineno_count * sizeof (alent); n_lineno_cache = (alent *) bfd_alloc (abfd, amt); if (n_lineno_cache != NULL) { @@ -4622,18 +4664,18 @@ coff_slurp_line_table (bfd *abfd, asection *asect) coff_symbol_type *sym; alent *old_ptr = func_table[i]; - /* Copy the function entry and update it. */ - *n_cache_ptr = *old_ptr; - sym = (coff_symbol_type *)n_cache_ptr->u.sym; - sym->lineno = n_cache_ptr; - n_cache_ptr++; - old_ptr++; - - /* Copy the line number entries. */ - while (old_ptr->line_number != 0) + /* Update the function entry. */ + sym = (coff_symbol_type *) old_ptr->u.sym; + /* PR binutils/17512: Point the lineno to where + this entry will be after the memcpy below. */ + sym->lineno = lineno_cache + (n_cache_ptr - n_lineno_cache); + /* Copy the function and line number entries. */ + do *n_cache_ptr++ = *old_ptr++; + while (old_ptr->line_number != 0); } - n_cache_ptr->line_number = 0; + BFD_ASSERT ((bfd_size_type) (n_cache_ptr - n_lineno_cache) == (amt / sizeof (alent))); + memcpy (lineno_cache, n_lineno_cache, amt); } bfd_release (abfd, func_table); @@ -4672,7 +4714,7 @@ coff_slurp_symbol_table (bfd * abfd) amt = obj_raw_syment_count (abfd); amt *= sizeof (unsigned int); - table_ptr = (unsigned int *) bfd_alloc (abfd, amt); + table_ptr = (unsigned int *) bfd_zalloc (abfd, amt); if (table_ptr == NULL) return FALSE; @@ -4686,14 +4728,17 @@ coff_slurp_symbol_table (bfd * abfd) { combined_entry_type *src = native_symbols + this_index; table_ptr[this_index] = number_of_symbols; - dst->symbol.the_bfd = abfd; + dst->symbol.the_bfd = abfd; + BFD_ASSERT (src->is_sym); dst->symbol.name = (char *) (src->u.syment._n._n_n._n_offset); /* We use the native name field to point to the cached field. */ src->u.syment._n._n_n._n_zeroes = (bfd_hostptr_t) dst; dst->symbol.section = coff_section_from_bfd_index (abfd, src->u.syment.n_scnum); dst->symbol.flags = 0; + /* PR 17512: file: 079-7098-0.001:0.1. */ + dst->symbol.value = 0; dst->done_lineno = FALSE; switch (src->u.syment.n_sclass) @@ -4980,9 +5025,9 @@ coff_slurp_symbol_table (bfd * abfd) } dst->native = src; - dst->symbol.udata.i = 0; dst->lineno = NULL; + this_index += (src->u.syment.n_numaux) + 1; dst++; number_of_symbols++; @@ -5065,13 +5110,13 @@ coff_classify_symbol (bfd *abfd, if (syment->n_value == 0) { asection *sec; - char buf[SYMNMLEN + 1]; - - sec = coff_section_from_bfd_index (abfd, syment->n_scnum); - if (sec != NULL - && (strcmp (bfd_get_section_name (abfd, sec), - _bfd_coff_internal_syment_name (abfd, syment, buf)) - == 0)) + char * name; + char buf[SYMNMLEN + 1]; + + name = _bfd_coff_internal_syment_name (abfd, syment, buf) + sec = coff_section_from_bfd_index (abfd, syment->n_scnum); + if (sec != NULL && name != NULL + && (strcmp (bfd_get_section_name (abfd, sec), name) == 0)) return COFF_SYMBOL_PE_SECTION; } #endif @@ -5142,6 +5187,7 @@ SUBSUBSECTION else if (ptr) \ coffsym = coff_symbol_from (abfd, ptr); \ if (coffsym != NULL \ + && coffsym->native->is_sym \ && coffsym->native->u.syment.n_scnum == 0) \ cache_ptr->addend = 0; \ else if (ptr && bfd_asymbol_bfd (ptr) == abfd \ @@ -5587,7 +5633,7 @@ static bfd_coff_backend_data ticoff1_swap_table = #endif #ifdef COFF_WITH_PE_BIGOBJ -/* The UUID for bigobj files. */ +/* The UID for bigobj files. */ static const char header_bigobj_classid[16] = { diff --git a/bfd/coffgen.c b/bfd/coffgen.c index 3f223897f66..a22f67a69d3 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -84,9 +84,8 @@ make_a_section_from_file (bfd *abfd, strings = _bfd_coff_read_string_table (abfd); if (strings == NULL) return FALSE; - /* FIXME: For extra safety, we should make sure that - strindex does not run us past the end, but right now we - don't know the length of the string table. */ + if ((bfd_size_type)(strindex + 2) >= obj_coff_strings_len (abfd)) + return FALSE; strings += strindex; name = (char *) bfd_alloc (abfd, (bfd_size_type) strlen (strings) + 1 + 1); @@ -464,6 +463,8 @@ _bfd_coff_internal_syment_name (bfd *abfd, if (strings == NULL) return NULL; } + if (sym->_n._n_n._n_offset >= obj_coff_strings_len (abfd)) + return NULL; return strings + sym->_n._n_n._n_offset; } } @@ -760,12 +761,14 @@ coff_renumber_symbols (bfd *bfd_ptr, int *first_undef) for (symbol_index = 0; symbol_index < symbol_count; symbol_index++) { coff_symbol_type *coff_symbol_ptr = coff_symbol_from (bfd_ptr, symbol_ptr_ptr[symbol_index]); + symbol_ptr_ptr[symbol_index]->udata.i = symbol_index; if (coff_symbol_ptr && coff_symbol_ptr->native) { combined_entry_type *s = coff_symbol_ptr->native; int i; + BFD_ASSERT (s->is_sym); if (s->u.syment.n_sclass == C_FILE) { if (last_file != NULL) @@ -810,6 +813,7 @@ coff_mangle_symbols (bfd *bfd_ptr) int i; combined_entry_type *s = coff_symbol_ptr->native; + BFD_ASSERT (s->is_sym); if (s->fix_value) { /* FIXME: We should use a union here. */ @@ -833,6 +837,8 @@ coff_mangle_symbols (bfd *bfd_ptr) for (i = 0; i < s->u.syment.n_numaux; i++) { combined_entry_type *a = s + i + 1; + + BFD_ASSERT (! a->is_sym); if (a->fix_tag) { a->u.auxent.x_sym.x_tagndx.l = @@ -876,6 +882,7 @@ coff_fix_symbol_name (bfd *abfd, } name_length = strlen (name); + BFD_ASSERT (native->is_sym); if (native->u.syment.n_sclass == C_FILE && native->u.syment.n_numaux > 0) { @@ -891,6 +898,7 @@ coff_fix_symbol_name (bfd *abfd, else strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); + BFD_ASSERT (! (native + 1)->is_sym); auxent = &(native + 1)->u.auxent; filnmlen = bfd_coff_filnmlen (abfd); @@ -993,6 +1001,8 @@ coff_write_symbol (bfd *abfd, void * buf; bfd_size_type symesz; + BFD_ASSERT (native->is_sym); + if (native->u.syment.n_sclass == C_FILE) symbol->flags |= BSF_DEBUGGING; @@ -1033,6 +1043,7 @@ coff_write_symbol (bfd *abfd, return FALSE; for (j = 0; j < native->u.syment.n_numaux; j++) { + BFD_ASSERT (! (native + j + 1)->is_sym); bfd_coff_swap_aux_out (abfd, &((native + j + 1)->u.auxent), type, n_sclass, (int) j, @@ -1078,10 +1089,12 @@ coff_write_alien_symbol (bfd *abfd, { symbol->name = ""; if (isym != NULL) - memset (isym, 0, sizeof(*isym)); + memset (isym, 0, sizeof (*isym)); return TRUE; } native = dummy; + native->is_sym = TRUE; + native[1].is_sym = FALSE; native->u.syment.n_type = T_NULL; native->u.syment.n_flags = 0; native->u.syment.n_numaux = 0; @@ -1108,7 +1121,7 @@ coff_write_alien_symbol (bfd *abfd, name to keep it from being put in the string table. */ symbol->name = ""; if (isym != NULL) - memset (isym, 0, sizeof(*isym)); + memset (isym, 0, sizeof (*isym)); return TRUE; } else @@ -1167,6 +1180,7 @@ coff_write_native_symbol (bfd *abfd, return TRUE; } + BFD_ASSERT (native->is_sym); /* If this symbol has an associated line number, we must store the symbol index in the line number field. We also tag the auxent to point to the right place in the lineno table. */ @@ -1276,8 +1290,9 @@ coff_write_symbols (bfd *abfd) symbol which has no associated section and we do not have to worry about this, all we need to know is that it is local. */ current_error_handler = bfd_set_error_handler (null_error_handler); + BFD_ASSERT (c_symbol->native->is_sym); sym_class = bfd_coff_classify_symbol (abfd, - &c_symbol->native->u.syment); + &c_symbol->native->u.syment); (void) bfd_set_error_handler (current_error_handler); n_sclass = &c_symbol->native->u.syment.n_sclass; @@ -1368,6 +1383,9 @@ coff_write_symbols (bfd *abfd) file name, nor does it go in the .debug section. */ maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; + else if (! c_symbol->native->is_sym) + maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; + else if (bfd_coff_symname_in_debug (abfd, &c_symbol->native->u.syment)) /* This symbol name is in the XCOFF .debug section. @@ -1458,6 +1476,7 @@ coff_write_linenumbers (bfd *abfd) { /* Found a linenumber entry, output. */ struct internal_lineno out; + memset ((void *) & out, 0, sizeof (out)); out.l_lnno = 0; out.l_addr.l_symndx = l->u.offset; @@ -1505,6 +1524,7 @@ coff_pointerize_aux (bfd *abfd, unsigned int type = symbol->u.syment.n_type; unsigned int n_sclass = symbol->u.syment.n_sclass; + BFD_ASSERT (symbol->is_sym); if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) { if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) @@ -1518,6 +1538,7 @@ coff_pointerize_aux (bfd *abfd, if (n_sclass == C_FILE) return; + BFD_ASSERT (! auxent->is_sym); /* Otherwise patch up. */ #define N_TMASK coff_data (abfd)->local_n_tmask #define N_BTSHFT coff_data (abfd)->local_n_btshft @@ -1545,7 +1566,7 @@ coff_pointerize_aux (bfd *abfd, we didn't want to go to the trouble until someone needed it. */ static char * -build_debug_section (bfd *abfd) +build_debug_section (bfd *abfd, asection ** sect_return) { char *debug_section; file_ptr position; @@ -1573,6 +1594,8 @@ build_debug_section (bfd *abfd) || bfd_bread (debug_section, sec_size, abfd) != sec_size || bfd_seek (abfd, position, SEEK_SET) != 0) return NULL; + + * sect_return = sect; return debug_section; } @@ -1635,7 +1658,9 @@ _bfd_coff_get_external_symbols (bfd *abfd) /* Read in the external strings. The strings are not loaded until they are needed. This is because we have no simple way of - detecting a missing string table in an archive. */ + detecting a missing string table in an archive. If the strings + are loaded then the STRINGS and STRINGS_LEN fields in the + coff_tdata structure will be set. */ const char * _bfd_coff_read_string_table (bfd *abfd) @@ -1685,7 +1710,13 @@ _bfd_coff_read_string_table (bfd *abfd) return NULL; } - strings = (char *) bfd_malloc (strsize); + strings = (char *) bfd_malloc (strsize + 1); + /* PR 17521 file: 079-54929-0.004. + A corrupt file could contain an index that points into the first + STRING_SIZE_SIZE bytes of the string table, so make sure that + they are zero. */ + memset (strings, 0, STRING_SIZE_SIZE); + if (strings == NULL) return NULL; @@ -1697,7 +1728,9 @@ _bfd_coff_read_string_table (bfd *abfd) } obj_coff_strings (abfd) = strings; - + obj_coff_strings_len (abfd) = strsize; + /* Terminate the string table, just in case. */ + strings[strsize] = 0; return strings; } @@ -1717,6 +1750,7 @@ _bfd_coff_free_symbols (bfd *abfd) { free (obj_coff_strings (abfd)); obj_coff_strings (abfd) = NULL; + obj_coff_strings_len (abfd) = 0; } return TRUE; } @@ -1737,21 +1771,22 @@ coff_get_normalized_symtab (bfd *abfd) char *raw_src; char *raw_end; const char *string_table = NULL; - char *debug_section = NULL; + asection * debug_sec = NULL; + char *debug_sec_data = NULL; bfd_size_type size; if (obj_raw_syments (abfd) != NULL) return obj_raw_syments (abfd); + if (! _bfd_coff_get_external_symbols (abfd)) + return NULL; + size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); internal = (combined_entry_type *) bfd_zalloc (abfd, size); if (internal == NULL && size != 0) return NULL; internal_end = internal + obj_raw_syment_count (abfd); - - if (! _bfd_coff_get_external_symbols (abfd)) - return NULL; - + raw_src = (char *) obj_coff_external_syms (abfd); /* Mark the end of the symbols. */ @@ -1766,23 +1801,29 @@ coff_get_normalized_symtab (bfd *abfd) raw_src < raw_end; raw_src += symesz, internal_ptr++) { - unsigned int i; + bfd_coff_swap_sym_in (abfd, (void *) raw_src, (void *) & internal_ptr->u.syment); symbol_ptr = internal_ptr; + internal_ptr->is_sym = TRUE; for (i = 0; i < symbol_ptr->u.syment.n_numaux; i++) { internal_ptr++; + /* PR 17512: Prevent buffer overrun. */ + if (internal_ptr >= internal_end) + return NULL; + raw_src += symesz; bfd_coff_swap_aux_in (abfd, (void *) raw_src, symbol_ptr->u.syment.n_type, symbol_ptr->u.syment.n_sclass, (int) i, symbol_ptr->u.syment.n_numaux, &(internal_ptr->u.auxent)); + internal_ptr->is_sym = FALSE; coff_pointerize_aux (abfd, internal, symbol_ptr, i, internal_ptr); } @@ -1796,12 +1837,18 @@ coff_get_normalized_symtab (bfd *abfd) for (internal_ptr = internal; internal_ptr < internal_end; internal_ptr++) { + BFD_ASSERT (internal_ptr->is_sym); + if (internal_ptr->u.syment.n_sclass == C_FILE && internal_ptr->u.syment.n_numaux > 0) { + combined_entry_type * aux = internal_ptr + 1; + /* Make a file symbol point to the name in the auxent, since the text ".file" is redundant. */ - if ((internal_ptr + 1)->u.auxent.x_file.x_n.x_zeroes == 0) + BFD_ASSERT (! aux->is_sym); + + if (aux->u.auxent.x_file.x_n.x_zeroes == 0) { /* The filename is a long one, point into the string table. */ if (string_table == NULL) @@ -1811,10 +1858,12 @@ coff_get_normalized_symtab (bfd *abfd) return NULL; } - internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - (string_table - + (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); + if ((bfd_size_type)(aux->u.auxent.x_file.x_n.x_offset) + >= obj_coff_strings_len (abfd)) + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _("<corrupt>"); + else + internal_ptr->u.syment._n._n_n._n_offset = + (bfd_hostptr_t) (string_table + (aux->u.auxent.x_file.x_n.x_offset)); } else { @@ -1824,15 +1873,15 @@ coff_get_normalized_symtab (bfd *abfd) if (internal_ptr->u.syment.n_numaux > 1 && coff_data (abfd)->pe) internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - copy_name (abfd, - (internal_ptr + 1)->u.auxent.x_file.x_fname, - internal_ptr->u.syment.n_numaux * symesz)); + (bfd_hostptr_t) + copy_name (abfd, + aux->u.auxent.x_file.x_fname, + internal_ptr->u.syment.n_numaux * symesz); else internal_ptr->u.syment._n._n_n._n_offset = ((bfd_hostptr_t) copy_name (abfd, - (internal_ptr + 1)->u.auxent.x_file.x_fname, + aux->u.auxent.x_file.x_fname, (size_t) bfd_coff_filnmlen (abfd))); } } @@ -1869,18 +1918,33 @@ coff_get_normalized_symtab (bfd *abfd) if (string_table == NULL) return NULL; } - internal_ptr->u.syment._n._n_n._n_offset = - ((bfd_hostptr_t) - (string_table - + internal_ptr->u.syment._n._n_n._n_offset)); + if (internal_ptr->u.syment._n._n_n._n_offset >= obj_coff_strings_len (abfd) + || string_table + internal_ptr->u.syment._n._n_n._n_offset < string_table) + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _("<corrupt>"); + else + internal_ptr->u.syment._n._n_n._n_offset = + ((bfd_hostptr_t) + (string_table + + internal_ptr->u.syment._n._n_n._n_offset)); } else { /* Long name in debug section. Very similar. */ - if (debug_section == NULL) - debug_section = build_debug_section (abfd); - internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) - (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + if (debug_sec_data == NULL) + debug_sec_data = build_debug_section (abfd, & debug_sec); + if (debug_sec_data != NULL) + { + BFD_ASSERT (debug_sec != NULL); + /* PR binutils/17512: Catch out of range offsets into the debug data. */ + if (internal_ptr->u.syment._n._n_n._n_offset > debug_sec->size + || debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset < debug_sec_data) + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) _("<corrupt>"); + else + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) + (debug_sec_data + internal_ptr->u.syment._n._n_n._n_offset); + } + else + internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) ""; } } internal_ptr += internal_ptr->u.syment.n_numaux; @@ -1913,7 +1977,7 @@ coff_make_empty_symbol (bfd *abfd) if (new_symbol == NULL) return NULL; new_symbol->symbol.section = 0; - new_symbol->native = 0; + new_symbol->native = NULL; new_symbol->lineno = NULL; new_symbol->done_lineno = FALSE; new_symbol->symbol.the_bfd = abfd; @@ -1939,6 +2003,7 @@ coff_bfd_make_debug_symbol (bfd *abfd, new_symbol->native = (combined_entry_type *) bfd_zalloc (abfd, amt); if (!new_symbol->native) return NULL; + new_symbol->native->is_sym = TRUE; new_symbol->symbol.section = bfd_abs_section_ptr; new_symbol->symbol.flags = BSF_DEBUGGING; new_symbol->lineno = NULL; @@ -1954,7 +2019,8 @@ coff_get_symbol_info (bfd *abfd, asymbol *symbol, symbol_info *ret) bfd_symbol_info (symbol, ret); if (coffsymbol (symbol)->native != NULL - && coffsymbol (symbol)->native->fix_value) + && coffsymbol (symbol)->native->fix_value + && coffsymbol (symbol)->native->is_sym) ret->value = coffsymbol (symbol)->native->u.syment.n_value - (bfd_hostptr_t) obj_raw_syments (abfd); } @@ -1969,7 +2035,8 @@ bfd_coff_get_syment (bfd *abfd, coff_symbol_type *csym; csym = coff_symbol_from (abfd, symbol); - if (csym == NULL || csym->native == NULL) + if (csym == NULL || csym->native == NULL + || ! csym->native->is_sym) { bfd_set_error (bfd_error_invalid_operation); return FALSE; @@ -2001,6 +2068,7 @@ bfd_coff_get_auxent (bfd *abfd, if (csym == NULL || csym->native == NULL + || ! csym->native->is_sym || indx >= csym->native->u.syment.n_numaux) { bfd_set_error (bfd_error_invalid_operation); @@ -2009,6 +2077,7 @@ bfd_coff_get_auxent (bfd *abfd, ent = csym->native + indx + 1; + BFD_ASSERT (! ent->is_sym); *pauxent = ent->u.auxent; if (ent->fix_tag) @@ -2062,6 +2131,15 @@ coff_print_symbol (bfd *abfd, fprintf (file, "[%3ld]", (long) (combined - root)); + /* PR 17512: file: 079-33786-0.001:0.1. */ + if (combined < obj_raw_syments (abfd) + || combined >= obj_raw_syments (abfd) + obj_raw_syment_count (abfd)) + { + fprintf (file, _("<corrupt info> %s"), symbol->name); + break; + } + + BFD_ASSERT (combined->is_sym); if (! combined->fix_value) val = (bfd_vma) combined->u.syment.n_value; else @@ -2081,6 +2159,7 @@ coff_print_symbol (bfd *abfd, combined_entry_type *auxp = combined + aux + 1; long tagndx; + BFD_ASSERT (! auxp->is_sym); if (auxp->fix_tag) tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; else @@ -2155,8 +2234,11 @@ coff_print_symbol (bfd *abfd, l++; while (l->line_number) { - fprintf (file, "\n%4d : ", l->line_number); - bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); + if (l->line_number > 0) + { + fprintf (file, "\n%4d : ", l->line_number); + bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); + } l++; } } @@ -2247,6 +2329,7 @@ coff_find_nearest_line_with_names (bfd *abfd, pend = p + cof->raw_syment_count; while (p < pend) { + BFD_ASSERT (p->is_sym); if (p->u.syment.n_sclass == C_FILE) break; p += 1 + p->u.syment.n_numaux; @@ -2270,6 +2353,7 @@ coff_find_nearest_line_with_names (bfd *abfd, p2 < pend; p2 += 1 + p2->u.syment.n_numaux) { + BFD_ASSERT (p2->is_sym); if (p2->u.syment.n_scnum > 0 && (section == coff_section_from_bfd_index (abfd, @@ -2281,6 +2365,8 @@ coff_find_nearest_line_with_names (bfd *abfd, break; } } + if (p2 >= pend) + break; file_addr = (bfd_vma) p2->u.syment.n_value; /* PR 11512: Include the section address of the function name symbol. */ @@ -2345,6 +2431,8 @@ coff_find_nearest_line_with_names (bfd *abfd, if (coff->native) { combined_entry_type *s = coff->native; + + BFD_ASSERT (s->is_sym); s = s + 1 + s->u.syment.n_numaux; /* In XCOFF a debugging symbol can follow the @@ -2357,6 +2445,7 @@ coff_find_nearest_line_with_names (bfd *abfd, { /* The linenumber is stored in the auxent. */ union internal_auxent *a = &((s + 1)->u.auxent); + line_base = a->x_sym.x_misc.x_lnsz.x_lnno; *line_ptr = line_base; } @@ -2478,6 +2567,7 @@ bfd_coff_set_symbol_class (bfd * abfd, if (native == NULL) return FALSE; + native->is_sym = TRUE; native->u.syment.n_type = T_NULL; native->u.syment.n_sclass = symbol_class; diff --git a/bfd/cofflink.c b/bfd/cofflink.c index 8c3f71bd0ba..2782795d3b8 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -2003,7 +2003,10 @@ _bfd_coff_link_input_bfd (struct coff_final_link_info *flaginfo, bfd *input_bfd) if (strings == NULL) return FALSE; } - filename = strings + auxp->x_file.x_n.x_offset; + if ((bfd_size_type) auxp->x_file.x_n.x_offset >= obj_coff_strings_len (input_bfd)) + filename = _("<corrupt>"); + else + filename = strings + auxp->x_file.x_n.x_offset; indx = _bfd_stringtab_add (flaginfo->strtab, filename, hash, copy); if (indx == (bfd_size_type) -1) diff --git a/bfd/elf.c b/bfd/elf.c index c8e659a27be..8b207ad872a 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -7269,8 +7269,12 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) hdr = &elf_tdata (abfd)->dynverref_hdr; - elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) + if (hdr->sh_info) + elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) bfd_zalloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed)); + else + elf_tdata (abfd)->verref = NULL; + if (elf_tdata (abfd)->verref == NULL) goto error_return; @@ -7430,8 +7434,12 @@ error_return_verref: else freeidx = ++maxidx; } - elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) + if (maxidx) + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef)); + else + elf_tdata (abfd)->verdef = NULL; + if (elf_tdata (abfd)->verdef == NULL) goto error_return; @@ -7572,16 +7580,12 @@ asymbol * _bfd_elf_make_empty_symbol (bfd *abfd) { elf_symbol_type *newsym; - bfd_size_type amt = sizeof (elf_symbol_type); - newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt); + newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof * newsym); if (!newsym) return NULL; - else - { - newsym->symbol.the_bfd = abfd; - return &newsym->symbol; - } + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; } void @@ -9408,7 +9412,7 @@ elfcore_write_lwpstatus (bfd *abfd, lwpstat.pr_lwpid = pid >> 16; lwpstat.pr_cursig = cursig; #if defined (HAVE_LWPSTATUS_T_PR_REG) - memcpy (lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg)); + memcpy (&lwpstat.pr_reg, gregs, sizeof (lwpstat.pr_reg)); #elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT) #if !defined(gregs) memcpy (lwpstat.pr_context.uc_mcontext.gregs, diff --git a/bfd/ieee.c b/bfd/ieee.c index 256e8f6693c..313834e7f7a 100644 --- a/bfd/ieee.c +++ b/bfd/ieee.c @@ -1312,7 +1312,8 @@ ieee_archive_p (bfd *abfd) /* Ignore the return value here. It doesn't matter if we don't read the entire buffer. We might have a very small ieee file. */ - bfd_bread ((void *) buffer, (bfd_size_type) sizeof (buffer), abfd); + if (bfd_bread ((void *) buffer, (bfd_size_type) sizeof (buffer), abfd) <= 0) + goto got_wrong_format_error; ieee->h.first_byte = buffer; ieee->h.input_p = buffer; @@ -1801,7 +1802,8 @@ ieee_object_p (bfd *abfd) goto fail; /* Read the first few bytes in to see if it makes sense. Ignore bfd_bread return value; The file might be very small. */ - bfd_bread ((void *) buffer, (bfd_size_type) sizeof (buffer), abfd); + if (bfd_bread ((void *) buffer, (bfd_size_type) sizeof (buffer), abfd) <= 0) + goto got_wrong_format; ieee->h.input_p = buffer; if (this_byte_and_next (&(ieee->h)) != Module_Beginning) diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h index 6162f2ee57c..6b6eb287e42 100644 --- a/bfd/libcoff-in.h +++ b/bfd/libcoff-in.h @@ -35,6 +35,7 @@ #define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) #define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) #define obj_coff_strings(bfd) (coff_data (bfd)->strings) +#define obj_coff_strings_len(bfd) (coff_data (bfd)->strings_len) #define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) #define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) #define obj_coff_strings_written(bfd) (coff_data (bfd)->strings_written) @@ -75,6 +76,8 @@ typedef struct coff_tdata /* The string table. May be NULL. Read by _bfd_coff_read_string_table. */ char *strings; + /* The length of the strings table. For error checking. */ + bfd_size_type strings_len; /* If this is TRUE, the strings may not be freed. */ bfd_boolean keep_strings; /* If this is TRUE, the strings have been written out already. */ diff --git a/bfd/libcoff.h b/bfd/libcoff.h index 12f19d07f6f..947998570ba 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -39,6 +39,7 @@ #define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) #define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) #define obj_coff_strings(bfd) (coff_data (bfd)->strings) +#define obj_coff_strings_len(bfd) (coff_data (bfd)->strings_len) #define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) #define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) #define obj_coff_strings_written(bfd) (coff_data (bfd)->strings_written) @@ -79,6 +80,8 @@ typedef struct coff_tdata /* The string table. May be NULL. Read by _bfd_coff_read_string_table. */ char *strings; + /* The length of the strings table. For error checking. */ + bfd_size_type strings_len; /* If this is TRUE, the strings may not be freed. */ bfd_boolean keep_strings; /* If this is TRUE, the strings have been written out already. */ @@ -627,7 +630,7 @@ extern bfd_boolean ppc_process_before_allocation typedef struct coff_ptr_struct { /* Remembers the offset from the first symbol in the file for - this symbol. Generated by coff_renumber_symbols. */ + this symbol. Generated by coff_renumber_symbols. */ unsigned int offset; /* Should the value of this symbol be renumbered. Used for @@ -635,15 +638,15 @@ typedef struct coff_ptr_struct unsigned int fix_value : 1; /* Should the tag field of this symbol be renumbered. - Created by coff_pointerize_aux. */ + Created by coff_pointerize_aux. */ unsigned int fix_tag : 1; /* Should the endidx field of this symbol be renumbered. - Created by coff_pointerize_aux. */ + Created by coff_pointerize_aux. */ unsigned int fix_end : 1; /* Should the x_csect.x_scnlen field be renumbered. - Created by coff_pointerize_aux. */ + Created by coff_pointerize_aux. */ unsigned int fix_scnlen : 1; /* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the @@ -651,12 +654,15 @@ typedef struct coff_ptr_struct unsigned int fix_line : 1; /* The container for the symbol structure as read and translated - from the file. */ + from the file. */ union { union internal_auxent auxent; struct internal_syment syment; } u; + + /* Selector for the union above. */ + bfd_boolean is_sym; } combined_entry_type; diff --git a/bfd/opncls.c b/bfd/opncls.c index a2a35f4e058..75af627d293 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -937,14 +937,19 @@ void * bfd_alloc (bfd *abfd, bfd_size_type size) { void *ret; + unsigned long ul_size = (unsigned long) size; - if (size != (unsigned long) size) + if (size != ul_size + /* A small negative size can result in objalloc_alloc allocating just + 1 byte of memory, but the caller will be expecting more. So catch + this case here. */ + || (size != 0 && (((ul_size + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1)) == 0))) { bfd_set_error (bfd_error_no_memory); return NULL; } - - ret = objalloc_alloc ((struct objalloc *) abfd->memory, (unsigned long) size); + + ret = objalloc_alloc ((struct objalloc *) abfd->memory, ul_size); if (ret == NULL) bfd_set_error (bfd_error_no_memory); return ret; @@ -965,8 +970,6 @@ DESCRIPTION void * bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) { - void *ret; - if ((nmemb | size) >= HALF_BFD_SIZE_TYPE && size != 0 && nmemb > ~(bfd_size_type) 0 / size) @@ -975,18 +978,7 @@ bfd_alloc2 (bfd *abfd, bfd_size_type nmemb, bfd_size_type size) return NULL; } - size *= nmemb; - - if (size != (unsigned long) size) - { - bfd_set_error (bfd_error_no_memory); - return NULL; - } - - ret = objalloc_alloc ((struct objalloc *) abfd->memory, (unsigned long) size); - if (ret == NULL) - bfd_set_error (bfd_error_no_memory); - return ret; + return bfd_alloc (abfd, size * nmemb); } /* @@ -1178,7 +1170,7 @@ bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out) asection *sect; unsigned long crc32; bfd_byte *contents; - int crc_offset; + unsigned int crc_offset; char *name; BFD_ASSERT (abfd); @@ -1196,10 +1188,13 @@ bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out) return NULL; } - /* Crc value is stored after the filename, aligned up to 4 bytes. */ + /* CRC value is stored after the filename, aligned up to 4 bytes. */ name = (char *) contents; - crc_offset = strlen (name) + 1; + /* PR 17597: avoid reading off the end of the buffer. */ + crc_offset = strnlen (name, bfd_get_section_size (sect)) + 1; crc_offset = (crc_offset + 3) & ~3; + if (crc_offset >= bfd_get_section_size (sect)) + return NULL; crc32 = bfd_get_32 (abfd, contents + crc_offset); @@ -1231,7 +1226,7 @@ bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len, { asection *sect; bfd_byte *contents; - int buildid_offset; + unsigned int buildid_offset; char *name; BFD_ASSERT (abfd); @@ -1252,7 +1247,9 @@ bfd_get_alt_debug_link_info (bfd * abfd, bfd_size_type *buildid_len, /* BuildID value is stored after the filename. */ name = (char *) contents; - buildid_offset = strlen (name) + 1; + buildid_offset = strnlen (name, bfd_get_section_size (sect)) + 1; + if (buildid_offset >= bfd_get_section_size (sect)) + return NULL; *buildid_len = bfd_get_section_size (sect) - buildid_offset; *buildid_out = bfd_malloc (*buildid_len); diff --git a/bfd/pe-mips.c b/bfd/pe-mips.c index ec7afc40ae5..57ec51fe19c 100644 --- a/bfd/pe-mips.c +++ b/bfd/pe-mips.c @@ -339,6 +339,8 @@ static reloc_howto_type howto_table[] = FALSE), /* Pcrel_offset. */ }; +#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; } @@ -379,7 +381,8 @@ static reloc_howto_type howto_table[] = cache_ptr->addend = - (ptr->section->vma + ptr->value); \ else \ cache_ptr->addend = 0; \ - if (ptr && howto_table[reloc.r_type].pc_relative) \ + if (ptr && reloc.r_type < NUM_HOWTOS \ + && howto_table[reloc.r_type].pc_relative) \ cache_ptr->addend += asect->vma; \ } @@ -509,9 +512,7 @@ coff_mips_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, { unsigned int i; - for (i = 0; - i < sizeof (howto_table) / sizeof (howto_table[0]); - i++) + for (i = 0; i < NUM_HOWTOS; i++) if (howto_table[i].name != NULL && strcasecmp (howto_table[i].name, r_name) == 0) return &howto_table[i]; diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index 1a5cb3135d5..13e39e48698 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -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,7 +521,7 @@ _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"), @@ -529,6 +545,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 +795,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 +1414,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,24 +1481,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 (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 @@ -1489,24 +1521,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 (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 @@ -1665,7 +1703,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"); @@ -1714,7 +1754,9 @@ 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: 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); @@ -1730,11 +1772,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 @@ -1755,29 +1798,37 @@ 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 + || (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); else for (i = 0; i < edt.num_names; ++i) { - bfd_vma name_ptr = bfd_get_32 (abfd, - data + - edt.npt_addr - + (i*4) - adj); + bfd_vma name_ptr; + bfd_vma ord; - char *name = (char *) data + name_ptr - adj; + ord = bfd_get_16 (abfd, data + edt.ot_addr + (i * 2) - adj); + name_ptr = bfd_get_32 (abfd, data + edt.npt_addr + (i * 4) - adj); - bfd_vma ord = bfd_get_16 (abfd, - data + - edt.ot_addr - + (i*2) - adj); - fprintf (file, - "\t[%4ld] %s\n", (long) ord, name); + if ((name_ptr - adj) >= datasize) + { + fprintf (file, _("\t[%4ld] <corrupt offset: %lx>\n"), + (long) ord, (long) name_ptr); + } + else + { + char * name = (char *) data + name_ptr - adj; + + fprintf (file, "\t[%4ld] %.*s\n", (long) ord, + (int)((char *)(data + datasize) - name), name); + } } free (data); @@ -2217,6 +2268,12 @@ static bfd_byte * rsrc_print_resource_directory (FILE * , bfd *, unsigned int, bfd_byte *, rsrc_regions *, bfd_vma); +/* Print the resource entry at DATA, with the text indented by INDENT. + Recusively calls rsrc_print_resource_directory to print the contents + of directory entries. + Returns the address of the end of the data associated with the entry + or section_end + 1 upon failure. */ + static bfd_byte * rsrc_print_resource_entries (FILE * file, bfd * abfd, @@ -2233,7 +2290,7 @@ rsrc_print_resource_entries (FILE * file, fprintf (file, _("%03x %*.s Entry: "), (int)(data - regions->section_start), indent, " "); - entry = (long) bfd_get_32 (abfd, data); + entry = (unsigned long) bfd_get_32 (abfd, data); if (is_name) { bfd_byte * name; @@ -2246,7 +2303,7 @@ rsrc_print_resource_entries (FILE * file, else name = regions->section_start + entry - rva_bias; - if (name + 2 < regions->section_end) + if (name + 2 < regions->section_end && name > regions->section_start) { unsigned int len; @@ -2256,20 +2313,38 @@ rsrc_print_resource_entries (FILE * file, len = bfd_get_16 (abfd, name); fprintf (file, _("name: [val: %08lx len %d]: "), entry, len); + if (name + 2 + len * 2 < regions->section_end) { /* This strange loop is to cope with multibyte characters. */ while (len --) { + char c; + name += 2; - fprintf (file, "%.1s", name); + c = * name; + /* Avoid printing control characters. */ + if (c > 0 && c < 32) + fprintf (file, "^%c", c + 64); + else + fprintf (file, "%.1s", name); } } else - fprintf (file, _("<corrupt string length: %#x>"), len); + { + fprintf (file, _("<corrupt string length: %#x>\n"), len); + /* PR binutils/17512: Do not try to continue decoding a + corrupted resource section. It is likely to end up with + reams of extraneous output. FIXME: We could probably + continue if we disable the printing of strings... */ + return regions->section_end + 1; + } } else - fprintf (file, _("<corrupt string offset: %#lx>"), entry); + { + fprintf (file, _("<corrupt string offset: %#lx>\n"), entry); + return regions->section_end + 1; + } } else fprintf (file, _("ID: %#08lx"), entry); @@ -2278,9 +2353,16 @@ rsrc_print_resource_entries (FILE * file, fprintf (file, _(", Value: %#08lx\n"), entry); if (HighBitSet (entry)) - return rsrc_print_resource_directory (file, abfd, indent + 1, - regions->section_start + WithoutHighBit (entry), - regions, rva_bias); + { + data = regions->section_start + WithoutHighBit (entry); + if (data <= regions->section_start || data > regions->section_end) + return regions->section_end + 1; + + /* FIXME: PR binutils/17512: A corrupt file could contain a loop + in the resource table. We need some way to detect this. */ + return rsrc_print_resource_directory (file, abfd, indent + 1, data, + regions, rva_bias); + } if (regions->section_start + entry + 16 >= regions->section_end) return regions->section_end + 1; @@ -2327,7 +2409,12 @@ rsrc_print_resource_directory (FILE * file, case 0: fprintf (file, "Type"); break; case 2: fprintf (file, "Name"); break; case 4: fprintf (file, "Language"); break; - default: fprintf (file, "<unknown>"); break; + default: + fprintf (file, _("<unknown directory type: %d>\n"), indent); + /* FIXME: For now we end the printing here. If in the + future more directory types are added to the RSRC spec + then we will need to change this. */ + return regions->section_end + 1; } fprintf (file, _(" Table: Char: %d, Time: %08lx, Ver: %d/%d, Num Names: %d, IDs: %d\n"), @@ -2449,10 +2536,10 @@ rsrc_print_section (bfd * abfd, void * vfile) } if (regions.strings_start != NULL) - fprintf (file, " String table starts at %03x\n", + fprintf (file, " String table starts at offset: %#03x\n", (int) (regions.strings_start - regions.section_start)); if (regions.resource_start != NULL) - fprintf (file, " Resources start at %03xx\n", + fprintf (file, " Resources start at offset: %#03x\n", (int) (regions.resource_start - regions.section_start)); free (regions.section_start); @@ -2514,16 +2601,29 @@ pe_print_debugdata (bfd * abfd, void * vfile) section->name); return TRUE; } + else if (section->size < size) + { + fprintf (file, + _("\nError: section %s contains the debug data starting address but it is too small\n"), + section->name); + return FALSE; + } fprintf (file, _("\nThere is a debug directory in %s at 0x%lx\n\n"), section->name, (unsigned long) addr); 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")); - /* Read the whole section. */ + /* Read the whole section. */ if (!bfd_malloc_and_get_section (abfd, section, &data)) { if (data != NULL) @@ -2540,7 +2640,7 @@ pe_print_debugdata (bfd * abfd, void * vfile) _bfd_XXi_swap_debugdir_in (abfd, ext, &idd); - if ((idd.Type) > IMAGE_NUMBEROF_DEBUG_TYPES) + if ((idd.Type) >= IMAGE_NUMBEROF_DEBUG_TYPES) type_name = debug_type_names[0]; else type_name = debug_type_names[idd.Type]; @@ -2946,7 +3046,7 @@ rsrc_count_entries (bfd * abfd, else name = datastart + entry - rva_bias; - if (name + 2 >= dataend) + if (name + 2 >= dataend || name < datastart) return dataend + 1; unsigned int len = bfd_get_16 (abfd, name); @@ -2957,10 +3057,14 @@ rsrc_count_entries (bfd * abfd, entry = (long) bfd_get_32 (abfd, data + 4); if (HighBitSet (entry)) - return rsrc_count_directory (abfd, - datastart, - datastart + WithoutHighBit (entry), - dataend, rva_bias); + { + data = datastart + WithoutHighBit (entry); + + if (data <= datastart || data >= dataend) + return dataend + 1; + + return rsrc_count_directory (abfd, datastart, data, dataend, rva_bias); + } if (datastart + entry + 16 >= dataend) return dataend + 1; @@ -3082,20 +3186,24 @@ rsrc_parse_entry (bfd * abfd, if (is_name) { - /* FIXME: Add range checking ? */ + bfd_byte * address; + if (HighBitSet (val)) { val = WithoutHighBit (val); - entry->name_id.name.len = bfd_get_16 (abfd, datastart + val); - entry->name_id.name.string = datastart + val + 2; + address = datastart + val; } else { - entry->name_id.name.len = bfd_get_16 (abfd, datastart + val - - rva_bias); - entry->name_id.name.string = datastart + val - rva_bias + 2; + address = datastart + val - rva_bias; } + + if (address + 3 > dataend) + return dataend; + + entry->name_id.name.len = bfd_get_16 (abfd, address); + entry->name_id.name.string = address + 2; } else entry->name_id.id = val; diff --git a/bfd/peicode.h b/bfd/peicode.h index 157879b478a..83653535554 100644 --- a/bfd/peicode.h +++ b/bfd/peicode.h @@ -271,6 +271,7 @@ pe_mkobject (bfd * abfd) /* in_reloc_p is architecture dependent. */ pe->in_reloc_p = in_reloc_p; + memset (& pe->pe_opthdr, 0, sizeof pe->pe_opthdr); return TRUE; } @@ -567,6 +568,7 @@ pe_ILF_make_a_symbol (pe_ILF_vars * vars, ent->u.syment.n_sclass = sclass; ent->u.syment.n_scnum = section->target_index; ent->u.syment._n._n_n._n_offset = (bfd_hostptr_t) sym; + ent->is_sym = TRUE; sym->symbol.the_bfd = vars->abfd; sym->symbol.name = vars->string_ptr; @@ -1313,7 +1315,7 @@ pe_bfd_object_p (bfd * abfd) /* Swap file header, so that we get the location for calling real_object_p. */ - bfd_coff_swap_filehdr_in (abfd, (PTR)&image_hdr, &internal_f); + bfd_coff_swap_filehdr_in (abfd, &image_hdr, &internal_f); if (! bfd_coff_bad_format_hook (abfd, &internal_f) || internal_f.f_opthdr > bfd_coff_aoutsz (abfd)) @@ -1327,16 +1329,21 @@ pe_bfd_object_p (bfd * abfd) if (opt_hdr_size != 0) { - PTR opthdr; + bfd_size_type amt = opt_hdr_size; + void * opthdr; - opthdr = bfd_alloc (abfd, opt_hdr_size); + /* PR 17521 file: 230-131433-0.004. */ + if (amt < sizeof (PEAOUTHDR)) + amt = sizeof (PEAOUTHDR); + + opthdr = bfd_zalloc (abfd, amt); if (opthdr == NULL) return NULL; if (bfd_bread (opthdr, opt_hdr_size, abfd) != (bfd_size_type) opt_hdr_size) return NULL; - bfd_coff_swap_aouthdr_in (abfd, opthdr, (PTR) & internal_a); + bfd_coff_swap_aouthdr_in (abfd, opthdr, & internal_a); } return coff_real_object_p (abfd, internal_f.f_nscns, &internal_f, diff --git a/bfd/tekhex.c b/bfd/tekhex.c index 2220d50c1e6..0328689c854 100644 --- a/bfd/tekhex.c +++ b/bfd/tekhex.c @@ -246,11 +246,12 @@ struct tekhex_data_list_struct typedef struct tekhex_data_list_struct tekhex_data_list_type; #define CHUNK_MASK 0x1fff +#define CHUNK_SPAN 32 struct data_struct { - char chunk_data[CHUNK_MASK + 1]; - char chunk_init[CHUNK_MASK + 1]; + unsigned char chunk_data[CHUNK_MASK + 1]; + unsigned char chunk_init[(CHUNK_MASK + 1 + CHUNK_SPAN - 1) / CHUNK_SPAN]; bfd_vma vma; struct data_struct *next; }; @@ -312,7 +313,7 @@ getsym (char *dstp, char **srcp, unsigned int *lenp) } static struct data_struct * -find_chunk (bfd *abfd, bfd_vma vma) +find_chunk (bfd *abfd, bfd_vma vma, bfd_boolean create) { struct data_struct *d = abfd->tdata.tekhex_data->data; @@ -320,7 +321,7 @@ find_chunk (bfd *abfd, bfd_vma vma) while (d && (d->vma) != vma) d = d->next; - if (!d) + if (!d && create) { /* No chunk for this address, so make one up. */ d = (struct data_struct *) @@ -339,11 +340,14 @@ find_chunk (bfd *abfd, bfd_vma vma) static void insert_byte (bfd *abfd, int value, bfd_vma addr) { - /* Find the chunk that this byte needs and put it in. */ - struct data_struct *d = find_chunk (abfd, addr); + if (value != 0) + { + /* Find the chunk that this byte needs and put it in. */ + struct data_struct *d = find_chunk (abfd, addr, TRUE); - d->chunk_data[addr & CHUNK_MASK] = value; - d->chunk_init[addr & CHUNK_MASK] = 1; + d->chunk_data[addr & CHUNK_MASK] = value; + d->chunk_init[(addr & CHUNK_MASK) / CHUNK_SPAN] = 1; + } } /* The first pass is to find the names of all the sections, and see @@ -352,7 +356,7 @@ insert_byte (bfd *abfd, int value, bfd_vma addr) static bfd_boolean first_phase (bfd *abfd, int type, char *src) { - asection *section = bfd_abs_section_ptr; + asection *section, *alt_section; unsigned int len; bfd_vma val; char sym[17]; /* A symbol can only be 16chars long. */ @@ -392,6 +396,7 @@ first_phase (bfd *abfd, int type, char *src) if (section == NULL) return FALSE; } + alt_section = NULL; while (*src) { switch (*src) @@ -439,6 +444,42 @@ first_phase (bfd *abfd, int type, char *src) new_symbol->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); else new_symbol->symbol.flags = BSF_LOCAL; + if (stype == '2' || stype == '6') + new_symbol->symbol.section = bfd_abs_section_ptr; + else if (stype == '3' || stype == '7') + { + if ((section->flags & SEC_DATA) == 0) + section->flags |= SEC_CODE; + else + { + if (alt_section == NULL) + alt_section = bfd_get_next_section_by_name (section); + if (alt_section == NULL) + alt_section = bfd_make_section_anyway_with_flags + (abfd, section->name, + (section->flags & ~SEC_DATA) | SEC_CODE); + if (alt_section == NULL) + return FALSE; + new_symbol->symbol.section = alt_section; + } + } + else if (stype == '4' || stype == '8') + { + if ((section->flags & SEC_CODE) == 0) + section->flags |= SEC_DATA; + else + { + if (alt_section == NULL) + alt_section = bfd_get_next_section_by_name (section); + if (alt_section == NULL) + alt_section = bfd_make_section_anyway_with_flags + (abfd, section->name, + (section->flags & ~SEC_CODE) | SEC_DATA); + if (alt_section == NULL) + return FALSE; + new_symbol->symbol.section = alt_section; + } + } if (!getvalue (&src, &val)) return FALSE; new_symbol->symbol.value = val - section->vma; @@ -589,22 +630,26 @@ move_section_contents (bfd *abfd, /* Get high bits of address. */ bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK; bfd_vma low_bits = addr & CHUNK_MASK; + bfd_boolean must_write = !get && *location != 0; - if (chunk_number != prev_number) - /* Different chunk, so move pointer. */ - d = find_chunk (abfd, chunk_number); + if (chunk_number != prev_number || (!d && must_write)) + { + /* Different chunk, so move pointer. */ + d = find_chunk (abfd, chunk_number, must_write); + prev_number = chunk_number; + } if (get) { - if (d->chunk_init[low_bits]) + if (d) *location = d->chunk_data[low_bits]; else *location = 0; } - else + else if (must_write) { d->chunk_data[low_bits] = *location; - d->chunk_init[low_bits] = (*location != 0); + d->chunk_init[low_bits / CHUNK_SPAN] = 1; } location++; @@ -632,7 +677,9 @@ tekhex_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long machine) { - return bfd_default_set_arch_mach (abfd, arch, machine); + /* Ignore errors about unknown architecture. */ + return (bfd_default_set_arch_mach (abfd, arch, machine) + || arch == bfd_arch_unknown); } /* We have to save up all the Tekhexords for a splurge before output. */ @@ -644,24 +691,6 @@ tekhex_set_section_contents (bfd *abfd, file_ptr offset, bfd_size_type bytes_to_do) { - if (! abfd->output_has_begun) - { - /* The first time around, allocate enough sections to hold all the chunks. */ - asection *s = abfd->sections; - bfd_vma vma; - - for (s = abfd->sections; s; s = s->next) - { - if (s->flags & SEC_LOAD) - { - for (vma = s->vma & ~(bfd_vma) CHUNK_MASK; - vma < s->vma + s->size; - vma += CHUNK_MASK) - find_chunk (abfd, vma); - } - } - } - if (section->flags & (SEC_LOAD | SEC_ALLOC)) { move_section_contents (abfd, section, locationp, offset, bytes_to_do, @@ -772,26 +801,17 @@ tekhex_write_object_contents (bfd *abfd) d = d->next) { int low; - - const int span = 32; int addr; /* Write it in blocks of 32 bytes. */ - for (addr = 0; addr < CHUNK_MASK + 1; addr += span) + for (addr = 0; addr < CHUNK_MASK + 1; addr += CHUNK_SPAN) { - int need = 0; - - /* Check to see if necessary. */ - for (low = 0; !need && low < span; low++) - if (d->chunk_init[addr + low]) - need = 1; - - if (need) + if (d->chunk_init[addr / CHUNK_SPAN]) { char *dst = buffer; writevalue (&dst, addr + d->vma); - for (low = 0; low < span; low++) + for (low = 0; low < CHUNK_SPAN; low++) { TOHEX (dst, d->chunk_data[addr + low]); dst += 2; diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index 1ca9c2e546d..952297451b9 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -4494,7 +4494,10 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *flinfo, if (strings == NULL) return FALSE; } - filename = strings + aux.x_file.x_n.x_offset; + if ((bfd_size_type) aux.x_file.x_n.x_offset >= obj_coff_strings_len (input_bfd)) + filename = _("<corrupt>"); + else + filename = strings + aux.x_file.x_n.x_offset; indx = _bfd_stringtab_add (flinfo->strtab, filename, hash, copy); if (indx == (bfd_size_type) -1) |