diff options
author | Alan Modra <amodra@gmail.com> | 2022-12-09 17:58:58 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2022-12-09 21:38:46 +1030 |
commit | 73425813c1b6286fd589fcf0ef9335e8240137a9 (patch) | |
tree | 41b84b5b2ddeb40c9fddd0e528827114a757bdb9 /bfd/elf32-mips.c | |
parent | 8b272d7671fb9af34fe14bd274e97f05bb299635 (diff) | |
download | gdb-73425813c1b6286fd589fcf0ef9335e8240137a9.zip gdb-73425813c1b6286fd589fcf0ef9335e8240137a9.tar.gz gdb-73425813c1b6286fd589fcf0ef9335e8240137a9.tar.bz2 |
PR28306, segfault in _bfd_mips_elf_reloc_unshuffle
Access to section data during relocation processing should be bounds
checked, as it is in bfd_perform_relocation. bfd_perform_relocation
does these checks after any special_function is called. So a reloc
special_function needs to do its own bounds checking before accessing
section data. This patch adds many such checks to the mips backend.
Checking mips relocs is not without some difficulty. See the comment
in _bfd_mips_reloc_offset_in_range. In a multitple reloc sequence
applied to the same location, relocs that may appear somewhere other
than the last one of the sequence need to be treated specially since
they apply to the addend for the next relocation rather than the
section contents. If the addend is in the section then it needs to be
checked but not when the addend is in the reloc. check_inplace
handles this situation. _bfd_mips_reloc_offset_in_range with
check_shuffle handles the case where contents are shuffled before
applying the relocation.
PR 28306
* elf32-mips.c (_bfd_mips_elf32_gprel16_reloc): Check reloc
address using _bfd_mips_reloc_offset_in_range.
(gprel32_with_gp, mips16_gprel_reloc): Likewise.
* elf64-mips.c (mips_elf64_gprel32_reloc): Likewise.
(mips16_gprel_reloc): Likewise.
* elfn32-mips.c (mips16_gprel_reloc): Likewise.
(gprel32_with_gp): Check reloc address using
bfd_reloc_offset_in_range.
* elfxx-mips.h (enum reloc_check): Define.
(_bfd_mips_reloc_offset_in_range): Declare.
* elfxx-mips.c (needs_shuffle): New function.
(_bfd_mips_elf_reloc_unshuffle, _bfd_mips_elf_reloc_shuffle): Use it.
(_bfd_mips_reloc_offset_in_range): New function.
(_bfd_mips_elf_gprel16_with_gp): Move reloc address checks to
partial_inplace handling. Use bfd_reloc_offset_in_range.
(_bfd_mips_elf_lo16_reloc): Check reloc address using
bfd_reloc_offset_in_range.
(_bfd_mips_elf_generic_reloc): Check reloc address using
_bfd_mips_reloc_offset_in_range.
(mips_elf_calculate_relocation): Check reloc address before calling
mips_elf_nullify_got_load.
(_bfd_mips_elf_check_relocs): Likewise.
(mips_elf_read_rel_addend): Add sec param, check reloc address
before reading. Adjust callers.
(mips_elf_add_lo16_rel_addend): Add sec param, adjust callers.
Diffstat (limited to 'bfd/elf32-mips.c')
-rw-r--r-- | bfd/elf32-mips.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 3f92df6..be28d1a 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -1790,6 +1790,10 @@ _bfd_mips_elf32_gprel16_reloc (bfd *abfd, arelent *reloc_entry, if (ret != bfd_reloc_ok) return ret; + if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry, + check_shuffle)) + return bfd_reloc_outofrange; + location = (bfd_byte *) data + reloc_entry->address; _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false, location); @@ -1857,7 +1861,8 @@ gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, relocation += symbol->section->output_section->vma; relocation += symbol->section->output_offset; - if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry, + check_inplace)) return bfd_reloc_outofrange; /* Set val to the offset into the section or symbol. */ @@ -1956,6 +1961,10 @@ mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, if (ret != bfd_reloc_ok) return ret; + if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry, + check_shuffle)) + return bfd_reloc_outofrange; + location = (bfd_byte *) data + reloc_entry->address; _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false, location); |