[binutils-gdb] m32r hi/lo reloc offset sanity checks

Alan Modra via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=be28dff7f92890b859cf365c4f2c7dd687da6c04

commit be28dff7f92890b859cf365c4f2c7dd687da6c04
Author: Alan Modra <[email protected]>
Date:   Mon Apr 20 15:41:14 2026 +0930

    m32r hi/lo reloc offset sanity checks
    
    This fixes another fuzzer attack.
    
            * elf32-m32r.c (m32r_elf_hi16_reloc): Properly check reloc offset.
            (m32r_elf_relocate_hi16): Add input_section param.  Return status.
            Sanity check reloc offsets before accessing section contents.
            Simplify sign extension.
            (m32r_elf_lo16_reloc): Sanity check reloc offset.  Simplify
            sign extension.  Remove unnecessary casts.
            (m32r_elf_relocate_section): Adjust m32r_elf_relocate_hi16 calls.

Diff:
---
 bfd/elf32-m32r.c | 48 +++++++++++++++++++++++++++---------------------
 1 file changed, 27 insertions(+), 21 deletions(-)

diff --git a/bfd/elf32-m32r.c b/bfd/elf32-m32r.c
index c10195b154d..68ef7122368 100644
--- a/bfd/elf32-m32r.c
+++ b/bfd/elf32-m32r.c
@@ -353,7 +353,7 @@ m32r_elf_free_cached_info (bfd *abfd)
 
 
 static bfd_reloc_status_type
-m32r_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+m32r_elf_hi16_reloc (bfd *abfd,
 		     arelent *reloc_entry,
 		     asymbol *symbol,
 		     void * data,
@@ -378,7 +378,8 @@ m32r_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
     }
 
   /* Sanity check the address (offset in section).  */
-  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
+				  reloc_entry->address))
     return bfd_reloc_outofrange;
 
   ret = bfd_reloc_ok;
@@ -413,8 +414,9 @@ m32r_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
 
 /* Handle an M32R ELF HI16 reloc.  */
 
-static void
+static bfd_reloc_status_type
 m32r_elf_relocate_hi16 (bfd *input_bfd,
+			asection *input_section,
 			int type,
 			Elf_Internal_Rela *relhi,
 			Elf_Internal_Rela *rello,
@@ -423,6 +425,11 @@ m32r_elf_relocate_hi16 (bfd *input_bfd,
 {
   unsigned long insn;
   bfd_vma addlo;
+  bfd_vma end = bfd_get_section_limit_octets (input_bfd, input_section);
+
+  if (relhi->r_offset > end || end - relhi->r_offset < 4
+      || rello->r_offset > end || end - rello->r_offset < 4)
+    return bfd_reloc_outofrange;
 
   insn = bfd_get_32 (input_bfd, contents + relhi->r_offset);
 
@@ -435,13 +442,13 @@ m32r_elf_relocate_hi16 (bfd *input_bfd,
   addend += ((insn & 0xffff) << 16) + addlo;
 
   /* Reaccount for sign extension of low part.  */
-  if (type == R_M32R_HI16_SLO
-      && (addend & 0x8000) != 0)
-    addend += 0x10000;
+  if (type == R_M32R_HI16_SLO)
+    addend += 0x8000;
 
   bfd_put_32 (input_bfd,
 	      (insn & 0xffff0000) | ((addend >> 16) & 0xffff),
 	      contents + relhi->r_offset);
+  return bfd_reloc_ok;
 }
 
 /* Do an R_M32R_LO16 relocation.  This is a straightforward 16 bit
@@ -470,6 +477,10 @@ m32r_elf_lo16_reloc (bfd *input_bfd,
       return bfd_reloc_ok;
     }
 
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, input_bfd, input_section,
+				  reloc_entry->address))
+    return bfd_reloc_outofrange;
+
   sdata = m32r_elf_section_data (input_section);
   if (sdata->m32r_hi16_list != NULL)
     {
@@ -488,16 +499,15 @@ m32r_elf_lo16_reloc (bfd *input_bfd,
 	     find the low 16 bits of the addend needed by the LO16.  */
 	  insn = bfd_get_32 (input_bfd, l->addr);
 	  vallo = ((bfd_get_32 (input_bfd, (bfd_byte *) data + reloc_entry->address)
-		   & 0xffff) ^ 0x8000) - 0x8000;
+		    & 0xffff) ^ 0x8000) - 0x8000;
 	  val = ((insn & 0xffff) << 16) + vallo;
 	  val += l->addend;
 
 	  /* Reaccount for sign extension of low part.  */
-	  if ((val & 0x8000) != 0)
-	    val += 0x10000;
+	  val += 0x8000;
 
-	  insn = (insn &~ (bfd_vma) 0xffff) | ((val >> 16) & 0xffff);
-	  bfd_put_32 (input_bfd, (bfd_vma) insn, l->addr);
+	  insn = (insn & ~0xffff) | ((val >> 16) & 0xffff);
+	  bfd_put_32 (input_bfd, insn, l->addr);
 
 	  next = l->next;
 	  free (l);
@@ -2451,11 +2461,9 @@ m32r_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 		continue;
 	      if (lorel < relend
 		  && ELF32_R_TYPE (lorel->r_info) == R_M32R_LO16)
-		{
-		  m32r_elf_relocate_hi16 (input_bfd, r_type, rel, lorel,
-					  contents, addend);
-		  r = bfd_reloc_ok;
-		}
+		r = m32r_elf_relocate_hi16 (input_bfd, input_section,
+					    r_type, rel, lorel,
+					    contents, addend);
 	      else
 		r = _bfd_relocate_contents (howto, input_bfd,
 					    addend, contents + offset);
@@ -2778,11 +2786,9 @@ m32r_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
 		  continue;
 		if (lorel < relend
 		    && ELF32_R_TYPE (lorel->r_info) == R_M32R_LO16)
-		  {
-		    m32r_elf_relocate_hi16 (input_bfd, r_type, rel, lorel,
-					    contents, relocation + addend);
-		    r = bfd_reloc_ok;
-		  }
+		  r = m32r_elf_relocate_hi16 (input_bfd, input_section,
+					      r_type, rel, lorel,
+					      contents, relocation + addend);
 		else
 		  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
 						contents, offset,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.