Harden PowerPC64 OPD handling against fuzzers
PowerPC64 ELFv1 object files should have at most one .opd section, and OPD handling in elf64-ppc.c makes use of this fact by caching some .opd section info in the per-object bfd.tdata. This was done to avoid another word in the target specific section data. Of course, fuzzers don't respect the ABI, and even non-malicious users can accidentally create multiple .opd sections. So it is better to avoid possible buffer overflows and other confusion when OPD handling for a second .opd section references data for the first .opd section, by keeping the data per-section. The patch also fixes a memory leak, and a corner case where I think we could hit an assertion in opd_entry_value or read out of bounds in ppc64_elf_branch_reloc doing a final link producing non-ppc64 output. (It's a really rare corner case because not only would you need to be linking ppc64 objects to non-ppc64 output, you'd also need a branch reloc symbol to be defined in a .opd section of a non-ppc64 input.) * elf64-ppc.c (is_ppc64_elf): Move earlier in file. (ppc64_elf_branch_reloc): Check symbol bfd before accessing ppc64 elf specific data structures. (struct ppc64_elf_obj_tdata): Move opd union.. (struct _ppc64_elf_section_data): ..to here. (ppc64_elf_before_check_relocs): Allow for opd sec_type already set to sec_opd. (ppc64_elf_check_relocs): Only set sec_type to sec_toc when unset. Error for unexpected toc relocs. (opd_entry_value): Return -1 when non-ppc64 rather than asserting. Check and set sec_type too. Adjust for changed location of contents and relocs. (ppc64_elf_relocate_section): Adjust for changed location of cached .opd relocs. (ppc64_elf_free_cached_info): New function. (bfd_elf64_bfd_free_cached_info): Define.
This commit is contained in:
parent
8261abd513
commit
6313825cbf
1 changed files with 60 additions and 27 deletions
|
@ -90,6 +90,7 @@ static bfd_vma opd_entry_value
|
|||
#define elf_backend_default_execstack 0
|
||||
|
||||
#define bfd_elf64_mkobject ppc64_elf_mkobject
|
||||
#define bfd_elf64_bfd_free_cached_info ppc64_elf_free_cached_info
|
||||
#define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup
|
||||
#define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup
|
||||
#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data
|
||||
|
@ -296,6 +297,10 @@ set_abiversion (bfd *abfd, int ver)
|
|||
elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI;
|
||||
elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI;
|
||||
}
|
||||
|
||||
#define is_ppc64_elf(bfd) \
|
||||
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
|
||||
&& elf_object_id (bfd) == PPC64_ELF_DATA)
|
||||
|
||||
/* Relocation HOWTO's. */
|
||||
/* Like other ELF RELA targets that don't apply multiple
|
||||
|
@ -1462,6 +1467,10 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|||
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
|
||||
input_section, output_bfd, error_message);
|
||||
|
||||
if (symbol->section->owner == NULL
|
||||
|| !is_ppc64_elf (symbol->section->owner))
|
||||
return bfd_reloc_continue;
|
||||
|
||||
if (strcmp (symbol->section->name, ".opd") == 0
|
||||
&& (symbol->section->owner->flags & DYNAMIC) == 0)
|
||||
{
|
||||
|
@ -1478,7 +1487,6 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|||
elf_symbol_type *elfsym = (elf_symbol_type *) symbol;
|
||||
|
||||
if (symbol->section->owner != abfd
|
||||
&& symbol->section->owner != NULL
|
||||
&& abiversion (symbol->section->owner) >= 2)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -1817,15 +1825,6 @@ struct ppc64_elf_obj_tdata
|
|||
sections means we potentially need one of these for each input bfd. */
|
||||
struct got_entry tlsld_got;
|
||||
|
||||
union
|
||||
{
|
||||
/* A copy of relocs before they are modified for --emit-relocs. */
|
||||
Elf_Internal_Rela *relocs;
|
||||
|
||||
/* Section contents. */
|
||||
bfd_byte *contents;
|
||||
} opd;
|
||||
|
||||
/* Nonzero if this bfd has small toc/got relocs, ie. that expect
|
||||
the reloc to be in the range -32768 to 32767. */
|
||||
unsigned int has_small_toc_reloc : 1;
|
||||
|
@ -1845,10 +1844,6 @@ struct ppc64_elf_obj_tdata
|
|||
#define ppc64_tlsld_got(bfd) \
|
||||
(&ppc64_elf_tdata (bfd)->tlsld_got)
|
||||
|
||||
#define is_ppc64_elf(bfd) \
|
||||
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
|
||||
&& elf_object_id (bfd) == PPC64_ELF_DATA)
|
||||
|
||||
/* Override the generic function because we store some extras. */
|
||||
|
||||
static bool
|
||||
|
@ -2016,6 +2011,15 @@ struct _ppc64_elf_section_data
|
|||
|
||||
/* After editing .opd, adjust references to opd local syms. */
|
||||
long *adjust;
|
||||
|
||||
union
|
||||
{
|
||||
/* A copy of relocs before they are modified for --emit-relocs. */
|
||||
Elf_Internal_Rela *relocs;
|
||||
|
||||
/* Section contents. */
|
||||
bfd_byte *contents;
|
||||
} u;
|
||||
} opd;
|
||||
|
||||
/* An array for toc sections, indexed by offset/8. */
|
||||
|
@ -4479,8 +4483,10 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
|
|||
|
||||
if (opd != NULL && opd->size != 0)
|
||||
{
|
||||
BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal);
|
||||
ppc64_elf_section_data (opd)->sec_type = sec_opd;
|
||||
if (ppc64_elf_section_data (opd)->sec_type == sec_normal)
|
||||
ppc64_elf_section_data (opd)->sec_type = sec_opd;
|
||||
else if (ppc64_elf_section_data (opd)->sec_type != sec_opd)
|
||||
BFD_FAIL ();
|
||||
|
||||
if (abiversion (ibfd) == 0)
|
||||
set_abiversion (ibfd, 1);
|
||||
|
@ -5234,7 +5240,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
return false;
|
||||
|
||||
ppc64_sec = ppc64_elf_section_data (sec);
|
||||
if (ppc64_sec->sec_type != sec_toc)
|
||||
if (ppc64_sec->sec_type == sec_normal)
|
||||
{
|
||||
bfd_size_type amt;
|
||||
|
||||
|
@ -5247,10 +5253,17 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
|
||||
if (ppc64_sec->u.toc.add == NULL)
|
||||
return false;
|
||||
BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
|
||||
ppc64_sec->sec_type = sec_toc;
|
||||
}
|
||||
BFD_ASSERT (rel->r_offset % 8 == 0);
|
||||
if (ppc64_sec->sec_type != sec_toc
|
||||
|| rel->r_offset % 8 != 0)
|
||||
{
|
||||
info->callbacks->einfo (_("%H: %s reloc unsupported here\n"),
|
||||
abfd, sec, rel->r_offset,
|
||||
ppc64_elf_howto_table[r_type]->name);
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return false;
|
||||
}
|
||||
ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
|
||||
ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
|
||||
|
||||
|
@ -5531,18 +5544,26 @@ opd_entry_value (asection *opd_sec,
|
|||
Elf_Internal_Rela *lo, *hi, *look;
|
||||
bfd_vma val;
|
||||
|
||||
if (!is_ppc64_elf (opd_bfd))
|
||||
return (bfd_vma) -1;
|
||||
|
||||
if (ppc64_elf_section_data (opd_sec)->sec_type == sec_normal)
|
||||
ppc64_elf_section_data (opd_sec)->sec_type = sec_opd;
|
||||
else if (ppc64_elf_section_data (opd_sec)->sec_type != sec_opd)
|
||||
return (bfd_vma) -1;
|
||||
|
||||
/* No relocs implies we are linking a --just-symbols object, or looking
|
||||
at a final linked executable with addr2line or somesuch. */
|
||||
if (opd_sec->reloc_count == 0)
|
||||
{
|
||||
bfd_byte *contents = ppc64_elf_tdata (opd_bfd)->opd.contents;
|
||||
bfd_byte *contents = ppc64_elf_section_data (opd_sec)->u.opd.u.contents;
|
||||
|
||||
if (contents == NULL)
|
||||
{
|
||||
if ((opd_sec->flags & SEC_HAS_CONTENTS) == 0
|
||||
|| !bfd_malloc_and_get_section (opd_bfd, opd_sec, &contents))
|
||||
return (bfd_vma) -1;
|
||||
ppc64_elf_tdata (opd_bfd)->opd.contents = contents;
|
||||
ppc64_elf_section_data (opd_sec)->u.opd.u.contents = contents;
|
||||
}
|
||||
|
||||
/* PR 17512: file: 64b9dfbb. */
|
||||
|
@ -5579,9 +5600,7 @@ opd_entry_value (asection *opd_sec,
|
|||
return val;
|
||||
}
|
||||
|
||||
BFD_ASSERT (is_ppc64_elf (opd_bfd));
|
||||
|
||||
relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs;
|
||||
relocs = ppc64_elf_section_data (opd_sec)->u.opd.u.relocs;
|
||||
if (relocs == NULL)
|
||||
relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, true);
|
||||
/* PR 17512: file: df8e1fd6. */
|
||||
|
@ -18055,13 +18074,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|
|||
adjusted. Worse, reloc symbol indices will be for the output
|
||||
file rather than the input. Save a copy of the relocs for
|
||||
opd_entry_value. */
|
||||
if (is_opd && (info->emitrelocations || bfd_link_relocatable (info)))
|
||||
if (is_opd
|
||||
&& (info->emitrelocations || bfd_link_relocatable (info))
|
||||
&& input_section->reloc_count != 0)
|
||||
{
|
||||
bfd_size_type amt;
|
||||
amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
|
||||
rel = bfd_alloc (input_bfd, amt);
|
||||
BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd.relocs == NULL);
|
||||
ppc64_elf_tdata (input_bfd)->opd.relocs = rel;
|
||||
ppc64_elf_section_data (input_section)->u.opd.u.relocs = rel;
|
||||
if (rel == NULL)
|
||||
return false;
|
||||
memcpy (rel, relocs, amt);
|
||||
|
@ -18376,6 +18396,19 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ppc64_elf_free_cached_info (bfd *abfd)
|
||||
{
|
||||
if (abfd->sections)
|
||||
for (asection *opd = bfd_get_section_by_name (abfd, ".opd");
|
||||
opd != NULL;
|
||||
opd = bfd_get_next_section_by_name (NULL, opd))
|
||||
if (opd->reloc_count == 0)
|
||||
free (ppc64_elf_section_data (opd)->u.opd.u.contents);
|
||||
|
||||
return _bfd_free_cached_info (abfd);
|
||||
}
|
||||
|
||||
#include "elf64-target.h"
|
||||
|
||||
/* FreeBSD support */
|
||||
|
|
Loading…
Add table
Reference in a new issue