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