[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