oss-fuzz mips32_64bit_reloc out-of-bounds accesses
Maciej W. Rozycki
macro@orcam.me.uk
Wed Mar 11 11:22:24 GMT 2026
On Thu, 5 Mar 2026, Alan Modra wrote:
> 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. However, taking notice of that result
> isn't sufficient since in little-endian mode a testcase could be
> crafted that put the high word out of bounds.
Would you be able to actually craft one?
> I notice also that mips32_64bit_reloc is called from a rela R_MIPS_64
> reloc howto. Using a rel R_MIPS_32 for the lower word can't be
> correct as it retrieves the addend from section contents rather than
> the reloc.
Umm, my oversight while fixing VxWorks support with commit 6b218502034c
("MIPS: Add o32 RELA relocations for VxWorks targets"); thanks for
catching!
> 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;
Please don't open-code sign-extension; use `_bfd_mips_elf_sign_extend' in
new code (I have a patch in the queue to optimise the function a little as
well, so please resist fiddling with it if you feel so inclined; it seems
like it would be good to make it static inline too).
Otherwise OK.
Maciej
More information about the Binutils
mailing list