diff options
author | Nick Clifton <nickc@redhat.com> | 2014-12-01 16:43:46 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-12-01 16:43:46 +0000 |
commit | 06614111d1be94b43ea8dd83805184d4e177bcea (patch) | |
tree | 7b83dc3944a96259e83bf4c949b237404f02c5bb /bfd | |
parent | 30b5e341f3bcb219718ad32cd0065670fd37e637 (diff) | |
download | gdb-06614111d1be94b43ea8dd83805184d4e177bcea.zip gdb-06614111d1be94b43ea8dd83805184d4e177bcea.tar.gz gdb-06614111d1be94b43ea8dd83805184d4e177bcea.tar.bz2 |
More fixes for memory access violations exposed by fuzzed binaries.
PR binutils/17512
* dwarf.h (struct dwarf_section): Add user_data field.
* dwarf.c (frame_need_space): Check for an over large register
number.
(display_debug_frames): Check the return value from
frame_need_space. Check for a CFA expression that is so long the
start address wraps around.
(debug_displays): Initialise the user_data field.
* objdump.c (load_specific_debug_section): Save the BFD section
pointer in the user_data field of the dwarf_section structure.
(free_debug_section): Update BFD section data when freeing section
contents.
* readelf.c (load_specific_debug_section): Initialise the
user_data field.
* archive.c (do_slurp_coff_armap): Add range checks to prevent
running off the end of the string table.
* compress.c (bfd_get_full_section_contents): Return a NULL
pointer for zero sized sections. Do not attempt to copy a buffer
onto itself.
* elf-attrs.c (_bfd_elf_parse_attributes): Check for an empty
header. Add range checks to avoid running off the end of the
section.
* elf.c (bfd_elf_get_str_section): Seek before allocating so that
if the seek fails, no memory is allocated.
(bfd_elf_string_from_elf_section): Do not allocate a string from a
non string section. It only leads to trouble later on.
(_bfd_elf_print_private_bfd_data): Check for there being too
little external dynamic data.
(bfd_section_from_shdr): Replace assertion with a failure mode.
(bfd_section_from_shdr): When walking a loaded group section use
the internal structure size, not the external size. Check for the
group section being empty.
* elf32-i386.c (elf_i386_rtype_to_howto): Replace assertion with a
failure mode.
* elfcode.h (elf_slurp_reloc_table): Likewise.
* reloc.c (bfd_perform_relocation): Avoid seg-fault if the howto
parameter is NULL.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 27 | ||||
-rw-r--r-- | bfd/archive.c | 11 | ||||
-rw-r--r-- | bfd/compress.c | 13 | ||||
-rw-r--r-- | bfd/elf-attrs.c | 16 | ||||
-rw-r--r-- | bfd/elf.c | 36 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 4 | ||||
-rw-r--r-- | bfd/elfcode.h | 4 | ||||
-rw-r--r-- | bfd/reloc.c | 4 |
8 files changed, 97 insertions, 18 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 8bcbc11..0489b79 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,30 @@ +2014-12-01 Nick Clifton <nickc@redhat.com> + + PR binutils/17512 + * archive.c (do_slurp_coff_armap): Add range checks to prevent + running off the end of the string table. + * compress.c (bfd_get_full_section_contents): Return a NULL + pointer for zero sized sections. Do not attempt to copy a buffer + onto itself. + * elf-attrs.c (_bfd_elf_parse_attributes): Check for an empty + header. Add range checks to avoid running off the end of the + section. + * elf.c (bfd_elf_get_str_section): Seek before allocating so that + if the seek fails, no memory is allocated. + (bfd_elf_string_from_elf_section): Do not allocate a string from a + non string section. It only leads to trouble later on. + (_bfd_elf_print_private_bfd_data): Check for there being too + little external dynamic data. + (bfd_section_from_shdr): Replace assertion with a failure mode. + (bfd_section_from_shdr): When walking a loaded group section use + the internal structure size, not the external size. Check for the + group section being empty. + * elf32-i386.c (elf_i386_rtype_to_howto): Replace assertion with a + failure mode. + * elfcode.h (elf_slurp_reloc_table): Likewise. + * reloc.c (bfd_perform_relocation): Avoid seg-fault if the howto + parameter is NULL. + 2014-11-30 Alan Modra <amodra@gmail.com> PR 16452, 16457 diff --git a/bfd/archive.c b/bfd/archive.c index df37996..0ab4f6e 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -1038,12 +1038,19 @@ do_slurp_coff_armap (bfd *abfd) } /* OK, build the carsyms. */ - for (i = 0; i < nsymz; i++) + for (i = 0; i < nsymz && stringsize > 0; i++) { + bfd_size_type len; + rawptr = raw_armap + i; carsyms->file_offset = swap ((bfd_byte *) rawptr); carsyms->name = stringbase; - stringbase += strlen (stringbase) + 1; + /* PR 17512: file: 4a1d50c1. */ + len = strnlen (stringbase, stringsize); + if (len < stringsize) + len ++; + stringbase += len; + stringsize -= len; carsyms++; } *stringbase = 0; diff --git a/bfd/compress.c b/bfd/compress.c index 20eef95..3fcbd78 100644 --- a/bfd/compress.c +++ b/bfd/compress.c @@ -152,7 +152,8 @@ DESCRIPTION return @var{*ptr} with memory malloc'd by this function. Return @code{TRUE} if the full section contents is retrieved - successfully. + successfully. If the section has no contents then this function + returns @code{TRUE} but @var{*ptr} is set to NULL. */ bfd_boolean @@ -172,7 +173,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) else sz = sec->size; if (sz == 0) - return TRUE; + { + *ptr = NULL; + return TRUE; + } switch (sec->compress_status) { @@ -183,6 +187,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) if (p == NULL) return FALSE; } + if (!bfd_get_section_contents (abfd, sec, p, 0, sz)) { if (*ptr != p) @@ -246,7 +251,9 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr) return FALSE; *ptr = p; } - memcpy (p, sec->contents, sz); + /* PR 17512; file: 5bc29788. */ + if (p != sec->contents) + memcpy (p, sec->contents, sz); return TRUE; default: diff --git a/bfd/elf-attrs.c b/bfd/elf-attrs.c index 6bc2944..25f7e26 100644 --- a/bfd/elf-attrs.c +++ b/bfd/elf-attrs.c @@ -430,9 +430,13 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) { bfd_byte *contents; bfd_byte *p; + bfd_byte *p_end; bfd_vma len; const char *std_sec; + /* PR 17512: file: 2844a11d. */ + if (hdr->sh_size == 0) + return; contents = (bfd_byte *) bfd_malloc (hdr->sh_size); if (!contents) return; @@ -443,11 +447,14 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) return; } p = contents; + p_end = p + hdr->sh_size; std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; + if (*(p++) == 'A') { len = hdr->sh_size - 1; - while (len > 0) + + while (len > 0 && p < p_end - 4) { unsigned namelen; bfd_vma section_len; @@ -477,7 +484,7 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) } p += namelen; - while (section_len > 0) + while (section_len > 0 && p < p_end) { int tag; unsigned int n; @@ -487,7 +494,10 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) tag = read_unsigned_leb128 (abfd, p, &n); p += n; - subsection_len = bfd_get_32 (abfd, p); + if (p < p_end - 4) + subsection_len = bfd_get_32 (abfd, p); + else + subsection_len = 0; p += 4; if (subsection_len == 0) break; @@ -297,13 +297,14 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 - || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL - || bfd_seek (abfd, offset, SEEK_SET) != 0) + || bfd_seek (abfd, offset, SEEK_SET) != 0 + || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL) shstrtab = NULL; else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) { if (bfd_get_error () != bfd_error_system_call) bfd_set_error (bfd_error_file_truncated); + bfd_release (abfd, shstrtab); shstrtab = NULL; /* Once we've failed to read it, make sure we don't keep trying. Otherwise, we'll keep allocating space for @@ -332,9 +333,19 @@ bfd_elf_string_from_elf_section (bfd *abfd, hdr = elf_elfsections (abfd)[shindex]; - if (hdr->contents == NULL - && bfd_elf_get_str_section (abfd, shindex) == NULL) - return NULL; + if (hdr->contents == NULL) + { + if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS) + { + /* PR 17512: file: f057ec89. */ + _bfd_error_handler (_("%B: attempt to load strings from a non-string section (number %d)"), + abfd, shindex); + return NULL; + } + + if (bfd_elf_get_str_section (abfd, shindex) == NULL) + return NULL; + } if (strindex >= hdr->sh_size) { @@ -636,6 +647,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) pointers. */ src = shdr->contents + shdr->sh_size; dest = (Elf_Internal_Group *) (shdr->contents + amt); + while (1) { unsigned int idx; @@ -1253,6 +1265,9 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; extdyn = dynbuf; + /* PR 17512: file: 6f427532. */ + if (s->size < extdynsize) + goto error_return; extdynend = extdyn + s->size; /* PR 17512: file: id:000006,sig:06,src:000000,op:flip4,pos:5664. Fix range check. */ @@ -1607,7 +1622,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (++ nesting > 3) { /* PR17512: A corrupt ELF binary might contain a recursive group of - sections, each the string indicies pointing to the next in the + sections, with each the string indicies pointing to the next in the loop. Detect this here, by refusing to load a section that we are already in the process of loading. We only trigger this test if we have nested at least three sections deep as normal ELF binaries @@ -1974,7 +1989,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) else p_hdr = &esdt->rel.hdr; - BFD_ASSERT (*p_hdr == NULL); + /* PR 17512: file: 0b4f81b7. */ + if (*p_hdr != NULL) + goto fail; amt = sizeof (*hdr2); hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); if (hdr2 == NULL) @@ -2031,15 +2048,18 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->contents != NULL) { Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; - unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE; + unsigned int n_elt = hdr->sh_size / sizeof (* idx); asection *s; + if (n_elt == 0) + goto fail; if (idx->flags & GRP_COMDAT) hdr->bfd_section->flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; /* We try to keep the same section order as it comes in. */ idx += n_elt; + while (--n_elt != 0) { --idx; diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 5c35d65..dcf37b1 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -379,7 +379,9 @@ elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) abfd, (int) r_type); indx = R_386_NONE; } - BFD_ASSERT (elf_howto_table [indx].type == r_type); + /* PR 17512: file: 0f67f69d. */ + if (elf_howto_table [indx].type != r_type) + return NULL; return &elf_howto_table[indx]; } diff --git a/bfd/elfcode.h b/bfd/elfcode.h index ec53c3b..d34e18e 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -1501,7 +1501,9 @@ elf_slurp_reloc_table (bfd *abfd, rel_hdr2 = d->rela.hdr; reloc_count2 = rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0; - BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2); + /* PR 17512: file: 0b4f81b7. */ + if (asect->reloc_count != reloc_count + reloc_count2) + return FALSE; BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset) || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); diff --git a/bfd/reloc.c b/bfd/reloc.c index dedfb6a..89e46f3 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -592,6 +592,10 @@ bfd_perform_relocation (bfd *abfd, return bfd_reloc_ok; } + /* PR 17512: file: 0f67f69d. */ + if (howto == NULL) + return bfd_reloc_undefined; + /* If we are not producing relocatable output, return an error if the symbol is not defined. An undefined weak symbol is considered to have a value of zero (SVR4 ABI, p. 4-27). */ |