diff options
author | Nick Clifton <nickc@redhat.com> | 2014-11-03 17:44:00 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-11-03 17:44:00 +0000 |
commit | 5a3f568b70bdfb91aacdfb66657b56d8c6d242f1 (patch) | |
tree | d11c8695362d773082a427bb3897d598a1ba0998 /bfd/coffgen.c | |
parent | ba241f2d5a6f1ac57e746d230892e27a70def4a6 (diff) | |
download | gdb-5a3f568b70bdfb91aacdfb66657b56d8c6d242f1.zip gdb-5a3f568b70bdfb91aacdfb66657b56d8c6d242f1.tar.gz gdb-5a3f568b70bdfb91aacdfb66657b56d8c6d242f1.tar.bz2 |
More fixes for buffer overruns instigated by corrupt binaries.
PR binutils/17512
* objdump.c (slurp_symtab): Fail gracefully if the table could not
be read.
(dump_relocs_in_section): Likewise.
* 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.
Diffstat (limited to 'bfd/coffgen.c')
-rw-r--r-- | bfd/coffgen.c | 72 |
1 files changed, 52 insertions, 20 deletions
diff --git a/bfd/coffgen.c b/bfd/coffgen.c index f18ddab..d0bf2c1a 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; } } @@ -1545,7 +1546,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 +1574,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; } @@ -1640,7 +1643,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) @@ -1702,6 +1707,7 @@ _bfd_coff_read_string_table (bfd *abfd) } obj_coff_strings (abfd) = strings; + obj_coff_strings_len (abfd) = strsize; return strings; } @@ -1722,6 +1728,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; } @@ -1742,13 +1749,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); - size = obj_raw_syment_count (abfd) * sizeof (combined_entry_type); + size = obj_raw_syment_count (abfd); + if (size == 0) + return NULL; + /* PR binutils/17512: Do not even try to load + a symbol table bigger than the entire file... */ + if (size >= (bfd_size_type) bfd_get_size (abfd)) + return NULL; + + size *= sizeof (combined_entry_type); internal = (combined_entry_type *) bfd_zalloc (abfd, size); if (internal == NULL && size != 0) return NULL; @@ -1819,11 +1835,14 @@ 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 + 1)->u.auxent.x_file.x_n.x_offset)); + if ((bfd_size_type)((internal_ptr + 1)->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 + + (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); } else { @@ -1878,18 +1897,31 @@ 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)) + 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) + 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; |