From b54509b84488023954f6974229b24fe6c993742b Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 6 Sep 2021 22:23:15 +0930 Subject: [PATCH] PR28307, segfault in ppc64_elf_toc64_reloc Adds missing bfd_reloc_offset_in_range checks to various relocation special_functions. PR 28307 * elf32-ppc.c (ppc_elf_addr16_ha_reloc): Range check reloc offset. * elf64-ppc.c (ppc64_elf_ha_reloc, ppc64_elf_brtaken_reloc): Likewise. (ppc64_elf_toc64_reloc, ppc64_elf_prefix_reloc): Likewise. --- bfd/elf32-ppc.c | 4 ++++ bfd/elf64-ppc.c | 28 +++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 93fbadf61bc..dd45da9d6a3 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -959,6 +959,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd, value >>= 16; octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~0x1fffc1; insn |= (value & 0xffc1) | ((value & 0x3e) << 15); diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 55c5e500d06..520804a0e1c 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1435,6 +1435,10 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, value = (bfd_signed_vma) value >> 16; octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~0x1fffc1; insn |= (value & 0xffc1) | ((value & 0x3e) << 15); @@ -1510,6 +1514,10 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, input_section, output_bfd, error_message); octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn &= ~(0x01 << 21); r_type = reloc_entry->howto->type; @@ -1655,11 +1663,15 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + TOCstart = _bfd_get_gp_value (input_section->output_section->owner); if (TOCstart == 0) TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner); - octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets); return bfd_reloc_ok; } @@ -1671,14 +1683,20 @@ ppc64_elf_prefix_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, { uint64_t insn; bfd_vma targ; + bfd_size_type octets; if (output_bfd != NULL) return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message); - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section); + if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, + input_section, octets)) + return bfd_reloc_outofrange; + + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); insn <<= 32; - insn |= bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address + 4); + insn |= bfd_get_32 (abfd, (bfd_byte *) data + octets + 4); targ = (symbol->section->output_section->vma + symbol->section->output_offset @@ -1697,8 +1715,8 @@ ppc64_elf_prefix_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, targ >>= reloc_entry->howto->rightshift; insn &= ~reloc_entry->howto->dst_mask; insn |= ((targ << 16) | (targ & 0xffff)) & reloc_entry->howto->dst_mask; - bfd_put_32 (abfd, insn >> 32, (bfd_byte *) data + reloc_entry->address); - bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address + 4); + bfd_put_32 (abfd, insn >> 32, (bfd_byte *) data + octets); + bfd_put_32 (abfd, insn, (bfd_byte *) data + octets + 4); if (reloc_entry->howto->complain_on_overflow == complain_overflow_signed && (targ + (1ULL << (reloc_entry->howto->bitsize - 1)) >= 1ULL << reloc_entry->howto->bitsize)) -- 2.30.2