summaryrefslogtreecommitdiff
path: root/bfd/elf64-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2021-09-06 22:23:15 +0930
committerAlan Modra <amodra@gmail.com>2021-09-07 10:41:29 +0930
commitb54509b84488023954f6974229b24fe6c993742b (patch)
treeabcbcdba27d2d4f5ddf767ea0c073609af32b01a /bfd/elf64-ppc.c
parentb4d9dd5c3576a8d6b1a59b11f8af1a3a2abd5fdc (diff)
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.
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r--bfd/elf64-ppc.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 55c5e500d0..520804a0e1 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))