From 7a6e0d89bb018cef0d8d13c497d8f340aa2a0fc8 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 12 Mar 2019 16:19:25 +1030 Subject: [PATCH] Don't use bfd_get_file_size in objdump Compressed debug sections can have uncompressed sizes that exceed the original file size, so we can't use bfd_get_file_size. objdump also used bfd_get_file_size to limit reloc section size, but I believe the underlying bug causing the PR22508 out of bounds buffer access was that we had an integer overflow when calculating the reloc buffer size. I've fixed that instead in most of the backends, som and vms-alpha being the exceptions. SOM and vmd-alpha have rather more serious bugs in their slurp_relocs routines that would need fixing first if we want to fuss about making them safe against fuzzed object files. The patch also fixes a number of other potential overflows by using the bfd_alloc2/malloc2/zalloc2 memory allocation functions. bfd/ * coffcode.h (buy_and_read): Delete unnecessary forward decl. Add nmemb parameter. Use bfd_alloc2. (coff_slurp_line_table): Use bfd_alloc2. Update buy_and_read calls. Delete assertion. (coff_slurp_symbol_table): Use bfd_alloc2 and bfd_zalloc2. (coff_slurp_reloc_table): Use bfd_alloc2. Update buy_and_read calls. * coffgen.c (coff_get_reloc_upper_bound): Ensure size calculation doesn't overflow. * elf.c (bfd_section_from_shdr): Use bfd_zalloc2. Style fix. (assign_section_numbers): Style fix. (swap_out_syms): Use bfd_malloc2. (_bfd_elf_get_reloc_upper_bound): Ensure size calculation doesn't overflow. (_bfd_elf_make_empty_symbol): Style fix. (elfobj_grok_stapsdt_note_1): Formatting. * elfcode.h (elf_object_p): Use bfd_alloc2. (elf_write_relocs, elf_write_shdrs_and_ehdr): Likewise. (elf_slurp_symbol_table): Use bfd_zalloc2. (elf_slurp_reloc_table): Use bfd_alloc2. (_bfd_elf_bfd_from_remote_memory): Use bfd_malloc2. * elf64-sparc (elf64_sparc_get_reloc_upper_bound): Ensure size calculation doesn't overflow. (elf64_sparc_get_dynamic_reloc_upper_bound): Likewise. * mach-o.c (bfd_mach_o_get_reloc_upper_bound): Likewise. * pdp11.c (get_reloc_upper_bound): Copy aoutx.h version. binutils/ * objdump.c (load_specific_debug_section): Don't compare section size against file size. (dump_relocs_in_section): Don't compare reloc size against file size. Print "failed to read relocs" on bfd_get_reloc_upper_bound error. --- bfd/ChangeLog | 28 ++++++++++++++++++++++++++++ bfd/coffcode.h | 51 +++++++++++++++++++++++++-------------------------- bfd/coffgen.c | 13 +++++++++++++ bfd/elf.c | 32 ++++++++++++++++++++++---------- bfd/elf64-sparc.c | 23 ++++++++++++++++++++++- bfd/elfcode.h | 39 +++++++++++++++++++-------------------- bfd/mach-o.c | 15 ++++++++++++++- bfd/pdp11.c | 42 +++++++++++++++++++++--------------------- binutils/ChangeLog | 7 +++++++ binutils/objdump.c | 37 +++++++++---------------------------- 10 files changed, 180 insertions(+), 107 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 18f1804..3e7d683 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,31 @@ +2019-03-12 Alan Modra + + * coffcode.h (buy_and_read): Delete unnecessary forward decl. Add + nmemb parameter. Use bfd_alloc2. + (coff_slurp_line_table): Use bfd_alloc2. Update buy_and_read calls. + Delete assertion. + (coff_slurp_symbol_table): Use bfd_alloc2 and bfd_zalloc2. + (coff_slurp_reloc_table): Use bfd_alloc2. Update buy_and_read calls. + * coffgen.c (coff_get_reloc_upper_bound): Ensure size calculation + doesn't overflow. + * elf.c (bfd_section_from_shdr): Use bfd_zalloc2. Style fix. + (assign_section_numbers): Style fix. + (swap_out_syms): Use bfd_malloc2. + (_bfd_elf_get_reloc_upper_bound): Ensure size calculation doesn't + overflow. + (_bfd_elf_make_empty_symbol): Style fix. + (elfobj_grok_stapsdt_note_1): Formatting. + * elfcode.h (elf_object_p): Use bfd_alloc2. + (elf_write_relocs, elf_write_shdrs_and_ehdr): Likewise. + (elf_slurp_symbol_table): Use bfd_zalloc2. + (elf_slurp_reloc_table): Use bfd_alloc2. + (_bfd_elf_bfd_from_remote_memory): Use bfd_malloc2. + * elf64-sparc (elf64_sparc_get_reloc_upper_bound): Ensure + size calculation doesn't overflow. + (elf64_sparc_get_dynamic_reloc_upper_bound): Likewise. + * mach-o.c (bfd_mach_o_get_reloc_upper_bound): Likewise. + * pdp11.c (get_reloc_upper_bound): Copy aoutx.h version. + 2019-03-08 Alan Modra PR 24311 diff --git a/bfd/coffcode.h b/bfd/coffcode.h index 2cea998..f4bfea0 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -423,8 +423,6 @@ static bfd_boolean coff_write_object_contents (bfd *) ATTRIBUTE_UNUSED; static bfd_boolean coff_set_section_contents (bfd *, asection *, const void *, file_ptr, bfd_size_type); -static void * buy_and_read - (bfd *, file_ptr, bfd_size_type); static bfd_boolean coff_slurp_line_table (bfd *, asection *); static bfd_boolean coff_slurp_symbol_table @@ -4197,12 +4195,14 @@ coff_set_section_contents (bfd * abfd, } static void * -buy_and_read (bfd *abfd, file_ptr where, bfd_size_type size) +buy_and_read (bfd *abfd, file_ptr where, + bfd_size_type nmemb, bfd_size_type size) { - void * area = bfd_alloc (abfd, size); + void *area = bfd_alloc2 (abfd, nmemb, size); if (!area) return NULL; + size *= nmemb; if (bfd_seek (abfd, where, SEEK_SET) != 0 || bfd_bread (area, size, abfd) != size) return NULL; @@ -4255,7 +4255,6 @@ coff_slurp_line_table (bfd *abfd, asection *asect) { LINENO *native_lineno; alent *lineno_cache; - bfd_size_type amt; unsigned int counter; alent *cache_ptr; bfd_vma prev_offset = 0; @@ -4278,13 +4277,15 @@ coff_slurp_line_table (bfd *abfd, asection *asect) return FALSE; } - amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent); - lineno_cache = (alent *) bfd_alloc (abfd, amt); + lineno_cache = (alent *) bfd_alloc2 (abfd, + (bfd_size_type) asect->lineno_count + 1, + sizeof (alent)); if (lineno_cache == NULL) return FALSE; - amt = (bfd_size_type) bfd_coff_linesz (abfd) * asect->lineno_count; - native_lineno = (LINENO *) buy_and_read (abfd, asect->line_filepos, amt); + native_lineno = (LINENO *) buy_and_read (abfd, asect->line_filepos, + asect->lineno_count, + bfd_coff_linesz (abfd)); if (native_lineno == NULL) { _bfd_error_handler @@ -4393,7 +4394,7 @@ coff_slurp_line_table (bfd *abfd, asection *asect) alent *n_lineno_cache; /* Create a table of functions. */ - func_table = (alent **) bfd_alloc (abfd, nbr_func * sizeof (alent *)); + func_table = (alent **) bfd_alloc2 (abfd, nbr_func, sizeof (alent *)); if (func_table != NULL) { alent **p = func_table; @@ -4409,8 +4410,8 @@ coff_slurp_line_table (bfd *abfd, asection *asect) qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent); /* Create the new sorted table. */ - amt = (bfd_size_type) asect->lineno_count * sizeof (alent); - n_lineno_cache = (alent *) bfd_alloc (abfd, amt); + n_lineno_cache = (alent *) bfd_alloc2 (abfd, asect->lineno_count, + sizeof (alent)); if (n_lineno_cache != NULL) { alent *n_cache_ptr = n_lineno_cache; @@ -4430,9 +4431,9 @@ coff_slurp_line_table (bfd *abfd, asection *asect) *n_cache_ptr++ = *old_ptr++; while (old_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); + memcpy (lineno_cache, n_lineno_cache, + asect->lineno_count * sizeof (alent)); } else ret = FALSE; @@ -4455,7 +4456,6 @@ coff_slurp_symbol_table (bfd * abfd) combined_entry_type *native_symbols; coff_symbol_type *cached_area; unsigned int *table_ptr; - bfd_size_type amt; unsigned int number_of_symbols = 0; bfd_boolean ret = TRUE; @@ -4467,15 +4467,14 @@ coff_slurp_symbol_table (bfd * abfd) return FALSE; /* Allocate enough room for all the symbols in cached form. */ - amt = obj_raw_syment_count (abfd); - amt *= sizeof (coff_symbol_type); - cached_area = (coff_symbol_type *) bfd_alloc (abfd, amt); + cached_area = (coff_symbol_type *) bfd_alloc2 (abfd, + obj_raw_syment_count (abfd), + sizeof (coff_symbol_type)); if (cached_area == NULL) return FALSE; - amt = obj_raw_syment_count (abfd); - amt *= sizeof (unsigned int); - table_ptr = (unsigned int *) bfd_zalloc (abfd, amt); + table_ptr = (unsigned int *) bfd_zalloc2 (abfd, obj_raw_syment_count (abfd), + sizeof (unsigned int)); if (table_ptr == NULL) return FALSE; @@ -4963,7 +4962,6 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols) arelent *reloc_cache; arelent *cache_ptr; unsigned int idx; - bfd_size_type amt; if (asect->relocation) return TRUE; @@ -4974,10 +4972,11 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols) if (!coff_slurp_symbol_table (abfd)) return FALSE; - amt = (bfd_size_type) bfd_coff_relsz (abfd) * asect->reloc_count; - native_relocs = (RELOC *) buy_and_read (abfd, asect->rel_filepos, amt); - amt = (bfd_size_type) asect->reloc_count * sizeof (arelent); - reloc_cache = (arelent *) bfd_alloc (abfd, amt); + native_relocs = (RELOC *) buy_and_read (abfd, asect->rel_filepos, + asect->reloc_count, + bfd_coff_relsz (abfd)); + reloc_cache = (arelent *) bfd_alloc2 (abfd, asect->reloc_count, + sizeof (arelent)); if (reloc_cache == NULL || native_relocs == NULL) return FALSE; diff --git a/bfd/coffgen.c b/bfd/coffgen.c index 5f5c5f6..5db35c7 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -37,6 +37,7 @@ coff_data (abfd). */ #include "sysdep.h" +#include #include "bfd.h" #include "libbfd.h" #include "coff/internal.h" @@ -2006,6 +2007,10 @@ coff_get_normalized_symtab (bfd *abfd) return internal; } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif long coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) { @@ -2014,8 +2019,16 @@ coff_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) bfd_set_error (bfd_error_invalid_operation); return -1; } + if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } return (asect->reloc_count + 1) * sizeof (arelent *); } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic pop +#endif asymbol * coff_make_empty_symbol (bfd *abfd) diff --git a/bfd/elf.c b/bfd/elf.c index 852b966..73fb869 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -2036,9 +2036,8 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) sections_being_created = NULL; if (sections_being_created == NULL) { - /* FIXME: It would be more efficient to attach this array to the bfd somehow. */ sections_being_created = (bfd_boolean *) - bfd_zalloc (abfd, elf_numsections (abfd) * sizeof (bfd_boolean)); + bfd_zalloc2 (abfd, elf_numsections (abfd), sizeof (bfd_boolean)); sections_being_created_abfd = abfd; } if (sections_being_created [shindex]) @@ -2259,7 +2258,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (entry->ndx == shindex) goto success; - entry = bfd_alloc (abfd, sizeof * entry); + entry = bfd_alloc (abfd, sizeof (*entry)); if (entry == NULL) goto fail; entry->ndx = shindex; @@ -3737,11 +3736,11 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name); if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF)) { - elf_section_list * entry; + elf_section_list *entry; BFD_ASSERT (elf_symtab_shndx_list (abfd) == NULL); - entry = bfd_zalloc (abfd, sizeof * entry); + entry = bfd_zalloc (abfd, sizeof (*entry)); entry->ndx = section_number++; elf_symtab_shndx_list (abfd) = entry; entry->hdr.sh_name @@ -7901,8 +7900,8 @@ swap_out_syms (bfd *abfd, symstrtab_hdr->sh_type = SHT_STRTAB; /* Allocate buffer to swap out the .strtab section. */ - symstrtab = (struct elf_sym_strtab *) bfd_malloc ((symcount + 1) - * sizeof (*symstrtab)); + symstrtab = (struct elf_sym_strtab *) bfd_malloc2 (symcount + 1, + sizeof (*symstrtab)); if (symstrtab == NULL) { _bfd_elf_strtab_free (stt); @@ -8269,12 +8268,25 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) return symtab_size; } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif long _bfd_elf_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr asect) { + + if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } return (asect->reloc_count + 1) * sizeof (arelent *); } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic pop +#endif /* Canonicalize the relocs. */ @@ -8753,7 +8765,7 @@ _bfd_elf_make_empty_symbol (bfd *abfd) { elf_symbol_type *newsym; - newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof * newsym); + newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (*newsym)); if (!newsym) return NULL; newsym->symbol.the_bfd = abfd; @@ -10233,8 +10245,8 @@ static bfd_boolean elfobj_grok_stapsdt_note_1 (bfd *abfd, Elf_Internal_Note *note) { struct sdt_note *cur = - (struct sdt_note *) bfd_alloc (abfd, sizeof (struct sdt_note) - + note->descsz); + (struct sdt_note *) bfd_alloc (abfd, + sizeof (struct sdt_note) + note->descsz); cur->next = (struct sdt_note *) (elf_tdata (abfd))->sdt_note_head; cur->size = (bfd_size_type) note->descsz; diff --git a/bfd/elf64-sparc.c b/bfd/elf64-sparc.c index bd29be3..f523ce7 100644 --- a/bfd/elf64-sparc.c +++ b/bfd/elf64-sparc.c @@ -19,6 +19,7 @@ MA 02110-1301, USA. */ #include "sysdep.h" +#include #include "bfd.h" #include "libbfd.h" #include "elf-bfd.h" @@ -33,16 +34,36 @@ section can represent up to two relocs, we must tell the user to allocate more space. */ +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif static long elf64_sparc_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) { + if (sec->reloc_count >= LONG_MAX / 2 / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } return (sec->reloc_count * 2 + 1) * sizeof (arelent *); } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic pop +#endif static long elf64_sparc_get_dynamic_reloc_upper_bound (bfd *abfd) { - return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 2; + long ret = _bfd_elf_get_dynamic_reloc_upper_bound (abfd); + if (ret > LONG_MAX / 2) + { + bfd_set_error (bfd_error_file_too_big); + ret = -1; + } + else if (ret > 0) + ret *= 2; + return ret; } /* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of diff --git a/bfd/elfcode.h b/bfd/elfcode.h index ec5ea76..a0487b0 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -503,7 +503,6 @@ elf_object_p (bfd *abfd) unsigned int shindex; const struct elf_backend_data *ebd; asection *s; - bfd_size_type amt; const bfd_target *target; /* Read in the ELF header in external format. */ @@ -688,14 +687,14 @@ elf_object_p (bfd *abfd) if (i_ehdrp->e_shnum > ((bfd_size_type) -1) / sizeof (*i_shdrp)) goto got_wrong_format_error; #endif - amt = sizeof (*i_shdrp) * (bfd_size_type) i_ehdrp->e_shnum; - i_shdrp = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); + i_shdrp = (Elf_Internal_Shdr *) bfd_alloc2 (abfd, i_ehdrp->e_shnum, + sizeof (*i_shdrp)); if (!i_shdrp) goto got_no_match; num_sec = i_ehdrp->e_shnum; elf_numsections (abfd) = num_sec; - amt = sizeof (i_shdrp) * num_sec; - elf_elfsections (abfd) = (Elf_Internal_Shdr **) bfd_alloc (abfd, amt); + elf_elfsections (abfd) + = (Elf_Internal_Shdr **) bfd_alloc2 (abfd, num_sec, sizeof (i_shdrp)); if (!elf_elfsections (abfd)) goto got_no_match; @@ -789,8 +788,9 @@ elf_object_p (bfd *abfd) if (bfd_get_file_size (abfd) > 0 && i_ehdrp->e_phnum > bfd_get_file_size (abfd)) goto got_no_match; - amt = (bfd_size_type) i_ehdrp->e_phnum * sizeof (*i_phdr); - elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); + elf_tdata (abfd)->phdr + = (Elf_Internal_Phdr *) bfd_alloc2 (abfd, i_ehdrp->e_phnum, + sizeof (*i_phdr)); if (elf_tdata (abfd)->phdr == NULL) goto got_no_match; if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0) @@ -903,7 +903,8 @@ elf_write_relocs (bfd *abfd, asection *sec, void *data) rela_hdr = elf_section_data (sec)->rel.hdr; rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count; - rela_hdr->contents = (unsigned char *) bfd_alloc (abfd, rela_hdr->sh_size); + rela_hdr->contents = (unsigned char *) bfd_alloc2 (abfd, sec->reloc_count, + rela_hdr->sh_entsize); if (rela_hdr->contents == NULL) { *failedp = TRUE; @@ -1040,9 +1041,8 @@ elf_write_shdrs_and_ehdr (bfd *abfd) i_shdrp[0]->sh_link = i_ehdrp->e_shstrndx; /* at this point we've concocted all the ELF sections... */ - amt = i_ehdrp->e_shnum; - amt *= sizeof (*x_shdrp); - x_shdrp = (Elf_External_Shdr *) bfd_alloc (abfd, amt); + x_shdrp = (Elf_External_Shdr *) bfd_alloc2 (abfd, i_ehdrp->e_shnum, + sizeof (*x_shdrp)); if (!x_shdrp) return FALSE; @@ -1053,6 +1053,7 @@ elf_write_shdrs_and_ehdr (bfd *abfd) #endif elf_swap_shdr_out (abfd, *i_shdrp, x_shdrp + count); } + amt = (bfd_size_type) i_ehdrp->e_shnum * sizeof (*x_shdrp); if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0 || bfd_bwrite (x_shdrp, amt, abfd) != amt) return FALSE; @@ -1152,7 +1153,6 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) Elf_External_Versym *xver; Elf_External_Versym *xverbuf = NULL; const struct elf_backend_data *ebd; - bfd_size_type amt; /* Read each raw ELF symbol, converting from external ELF form to internal ELF form, and then using the information to create a @@ -1197,9 +1197,8 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic) if (isymbuf == NULL) return -1; - amt = symcount; - amt *= sizeof (elf_symbol_type); - symbase = (elf_symbol_type *) bfd_zalloc (abfd, amt); + symbase = (elf_symbol_type *) bfd_zalloc2 (abfd, symcount, + sizeof (elf_symbol_type)); if (symbase == (elf_symbol_type *) NULL) goto error_return; @@ -1519,7 +1518,6 @@ elf_slurp_reloc_table (bfd *abfd, bfd_size_type reloc_count; bfd_size_type reloc_count2; arelent *relents; - bfd_size_type amt; if (asect->relocation != NULL) return TRUE; @@ -1557,8 +1555,8 @@ elf_slurp_reloc_table (bfd *abfd, reloc_count2 = 0; } - amt = (reloc_count + reloc_count2) * sizeof (arelent); - relents = (arelent *) bfd_alloc (abfd, amt); + relents = (arelent *) bfd_alloc2 (abfd, reloc_count + reloc_count2, + sizeof (arelent)); if (relents == NULL) return FALSE; @@ -1713,8 +1711,9 @@ NAME(_bfd_elf,bfd_from_remote_memory) return NULL; } - x_phdrs = (Elf_External_Phdr *) - bfd_malloc (i_ehdr.e_phnum * (sizeof *x_phdrs + sizeof *i_phdrs)); + x_phdrs + = (Elf_External_Phdr *) bfd_malloc2 (i_ehdr.e_phnum, + sizeof (*x_phdrs) + sizeof (*i_phdrs)); if (x_phdrs == NULL) return NULL; err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs, diff --git a/bfd/mach-o.c b/bfd/mach-o.c index 917335d..a9ca313 100644 --- a/bfd/mach-o.c +++ b/bfd/mach-o.c @@ -19,6 +19,7 @@ MA 02110-1301, USA. */ #include "sysdep.h" +#include #include "bfd.h" #include "libbfd.h" #include "libiberty.h" @@ -1416,12 +1417,24 @@ bfd_mach_o_write_dyld_info (bfd *abfd, bfd_mach_o_load_command *command) return TRUE; } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif long bfd_mach_o_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *asect) { - return (asect->reloc_count + 1) * sizeof (arelent *); + if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } + return (asect->reloc_count + 1) * sizeof (arelent *); } +#if GCC_VERSION >= 4003 +# pragma GCC diagnostic pop +#endif /* In addition to the need to byte-swap the symbol number, the bit positions of the fields in the relocation information vary per target endian-ness. */ diff --git a/bfd/pdp11.c b/bfd/pdp11.c index b16c78f..1d34047 100644 --- a/bfd/pdp11.c +++ b/bfd/pdp11.c @@ -66,6 +66,7 @@ && N_MAGIC(x) != ZMAGIC) #include "sysdep.h" +#include #include "bfd.h" #define external_exec pdp11_external_exec @@ -1980,6 +1981,8 @@ NAME (aout, canonicalize_reloc) (bfd *abfd, long NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) { + bfd_size_type count; + if (bfd_get_format (abfd) != bfd_object) { bfd_set_error (bfd_error_invalid_operation); @@ -1987,28 +1990,25 @@ NAME (aout, get_reloc_upper_bound) (bfd *abfd, sec_ptr asect) } if (asect->flags & SEC_CONSTRUCTOR) - return (sizeof (arelent *) * (asect->reloc_count + 1)); - - if (asect == obj_datasec (abfd)) - return (sizeof (arelent *) - * ((exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd)) - + 1)); - - if (asect == obj_textsec (abfd)) - return (sizeof (arelent *) - * ((exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd)) - + 1)); - - /* TODO: why are there two if statements for obj_bsssec()? */ - - if (asect == obj_bsssec (abfd)) - return sizeof (arelent *); - - if (asect == obj_bsssec (abfd)) - return 0; + count = asect->reloc_count; + else if (asect == obj_datasec (abfd)) + count = exec_hdr (abfd)->a_drsize / obj_reloc_entry_size (abfd); + else if (asect == obj_textsec (abfd)) + count = exec_hdr (abfd)->a_trsize / obj_reloc_entry_size (abfd); + else if (asect == obj_bsssec (abfd)) + count = 0; + else + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } - bfd_set_error (bfd_error_invalid_operation); - return -1; + if (count >= LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } + return (count + 1) * sizeof (arelent *); } diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 605a7b3..d62f94a 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,10 @@ +2019-03-12 Alan Modra + + * objdump.c (load_specific_debug_section): Don't compare section + size against file size. + (dump_relocs_in_section): Don't compare reloc size against file size. + Print "failed to read relocs" on bfd_get_reloc_upper_bound error. + 2019-03-05 Nick Clifton PR 24295 diff --git a/binutils/objdump.c b/binutils/objdump.c index ab091c1..3ef2716 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -2695,7 +2695,7 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, section->user_data = sec; section->size = bfd_get_section_size (sec); amt = section->size + 1; - if (amt == 0 || amt > bfd_get_file_size (abfd)) + if (amt == 0) { section->start = NULL; free_debug_section (debug); @@ -3640,47 +3640,28 @@ dump_relocs_in_section (bfd *abfd, || ((section->flags & SEC_RELOC) == 0)) return; - relsize = bfd_get_reloc_upper_bound (abfd, section); - if (relsize < 0) - bfd_fatal (bfd_get_filename (abfd)); - printf ("RELOCATION RECORDS FOR [%s]:", sanitize_string (section->name)); + relsize = bfd_get_reloc_upper_bound (abfd, section); if (relsize == 0) { printf (" (none)\n\n"); return; } - if ((bfd_get_file_flags (abfd) & (BFD_IN_MEMORY | BFD_LINKER_CREATED)) == 0 - && (/* Check that the size of the relocs is reasonable. Note that some - file formats, eg aout, can have relocs whose internal size is - larger than their external size, thus we check the size divided - by four against the file size. See PR 23931 for an example of - this. */ - ((ufile_ptr) (relsize / 4) > bfd_get_file_size (abfd)) - /* Also check the section's reloc count since if this is negative - (or very large) the computation in bfd_get_reloc_upper_bound - may have resulted in returning a small, positive integer. - See PR 22508 for a reproducer. - - Note - we check against file size rather than section size as - it is possible for there to be more relocs that apply to a - section than there are bytes in that section. */ - || (section->reloc_count > bfd_get_file_size (abfd)))) + if (relsize < 0) + relcount = relsize; + else { - printf (" (too many: %#x relocs)\n", section->reloc_count); - bfd_set_error (bfd_error_file_truncated); - bfd_fatal (bfd_get_filename (abfd)); + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms); } - relpp = (arelent **) xmalloc (relsize); - relcount = bfd_canonicalize_reloc (abfd, section, relpp, syms); - if (relcount < 0) { printf ("\n"); - non_fatal (_("failed to read relocs in: %s"), sanitize_string (bfd_get_filename (abfd))); + non_fatal (_("failed to read relocs in: %s"), + sanitize_string (bfd_get_filename (abfd))); bfd_fatal (_("error message was")); } else if (relcount == 0) -- 2.7.4