[binutils-gdb] oss-fuzz addr2line mips32_64bit_reloc out-of-bounds accesses
Alan Modra
amodra@sourceware.org
Thu Mar 12 08:00:44 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=c8b798145ff623a87ec4d39015cf832b0160899d
commit c8b798145ff623a87ec4d39015cf832b0160899d
Author: Alan Modra <amodra@gmail.com>
Date: Thu Mar 12 18:23:28 2026 +1030
oss-fuzz addr2line mips32_64bit_reloc out-of-bounds accesses
The code sign extending the low 32 bits into the high 32 bits in this
function does not have any address checking as it ignores the result
from bfd_perform_relocation. Even if it did take notice that isn't
sufficient. In little-endian mode a testcase could be crafted with
the low word at the end of a section which would put the high word out
of bounds.
I notice also that mips32_64bit_reloc is called from a rela R_MIPS_64
reloc howto. Using a rel R_MIPS_32 howto for the lower word can't be
correct as it retrieves the addend from section contents rather than
the reloc.
Fix both of these problems by performing the entire normal 64-bit
relocation first rather than trying to be clever doing it by pieces.
Nowadays config.bfd ensures that mips elf targets always have a 64-bit
bfd.
Also, don't trim addends to 32 bits for relocatable linking or gas.
That doesn't seem necessary and in any case wasn't done properly for
the rela case, where the addend is not in section contents but in the
relocation. Note that relocatable linking will usually be done by
elfxx-mips.c:_bfd_mips_elf_relocate_section. The main use of these
howtos is in gas and bfd_simple_get_relocated_section_contents.
* elf32-mips.c (mips32_64bit_reloc): Rewrite.
Diff:
---
bfd/elf32-mips.c | 35 +++++++++++------------------------
1 file changed, 11 insertions(+), 24 deletions(-)
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 0712cbb0962..cef0c937d26 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -3339,35 +3339,22 @@ gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
sign extension. */
static bfd_reloc_status_type
-mips32_64bit_reloc (bfd *abfd, arelent *reloc_entry,
- asymbol *symbol ATTRIBUTE_UNUSED,
+mips32_64bit_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
{
bfd_reloc_status_type r;
- arelent reloc32;
- unsigned long val;
- bfd_size_type addr;
-
- /* Do a normal 32 bit relocation on the lower 32 bits. */
- reloc32 = *reloc_entry;
- if (bfd_big_endian (abfd))
- reloc32.address += 4;
- reloc32.howto = &elf_mips_howto_table_rel[R_MIPS_32];
- r = bfd_perform_relocation (abfd, &reloc32, data, input_section,
- output_bfd, error_message);
-
- /* Sign extend into the upper 32 bits. */
- val = bfd_get_32 (abfd, (bfd_byte *) data + reloc32.address);
- if ((val & 0x80000000) != 0)
- val = 0xffffffff;
- else
- val = 0;
- addr = reloc_entry->address;
- if (bfd_little_endian (abfd))
- addr += 4;
- bfd_put_32 (abfd, val, (bfd_byte *) data + addr);
+ r = _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+ if (r == bfd_reloc_ok && output_bfd == NULL)
+ {
+ /* When final linking, sign extend low word into the upper word. */
+ bfd_byte *loc = (bfd_byte *) data + reloc_entry->address;
+ bfd_vma val = bfd_get_64 (abfd, loc);
+ val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+ bfd_put_64 (abfd, val, loc);
+ }
return r;
}
More information about the Binutils-cvs
mailing list