PR33919 Out-of-bounds read in XCOFF relocation processing

Message ID abc-fUj6X4ivn9IR@squeak.grove.modra.org
State New
Headers
Series PR33919 Out-of-bounds read in XCOFF relocation processing |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

Alan Modra March 15, 2026, 11:19 p.m. UTC
  PR 33919
	* coff-rs6000.c (xcoff_calculate_relocation): Don't use explicit
	array size.
	(xcoff_complain_overflow): Likewise.
	(xcoff_rtype2howto): Return a NULL howto rather than aborting.
	(_bfd_xcoff_reloc_name_lookup): Use ARRAY_SIZE.
	(xcoff_ppc_relocate_section): Sanity check reloc r_type before
	accessing xcoff_howto_table.  Print r_type using %#x.  Remove
	now redundant later reloc r_type sanity check.
	* coff64-rs6000.c: Similarly.
	* libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Don't define.
	(XCOFF_MAX_COMPLAIN_OVERFLOW): Don't define.
  

Patch

diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 62caae64f4e..00e0f5442f7 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -155,8 +155,7 @@  static xcoff_complain_function xcoff_complain_overflow_bitfield_func;
 static xcoff_complain_function xcoff_complain_overflow_signed_func;
 static xcoff_complain_function xcoff_complain_overflow_unsigned_func;
 
-xcoff_reloc_function *const
-xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
+xcoff_reloc_function *const xcoff_calculate_relocation[] =
 {
   xcoff_reloc_type_pos,  /* R_POS   (0x00) */
   xcoff_reloc_type_neg,  /* R_NEG   (0x01) */
@@ -210,8 +209,7 @@  xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
   xcoff_reloc_type_toc,  /* R_TOCL    (0x31) */
 };
 
-xcoff_complain_function *const
-xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW] =
+xcoff_complain_function *const xcoff_complain_overflow[] =
 {
   xcoff_complain_overflow_dont_func,
   xcoff_complain_overflow_bitfield_func,
@@ -1158,8 +1156,11 @@  reloc_howto_type xcoff_howto_table[] =
 void
 xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal)
 {
-  if (internal->r_type > R_TOCL)
-    abort ();
+  if (internal->r_type >= ARRAY_SIZE (xcoff_howto_table))
+    {
+      relent->howto = NULL;
+      return;
+    }
 
   /* Default howto layout works most of the time */
   relent->howto = &xcoff_howto_table[internal->r_type];
@@ -1183,7 +1184,7 @@  xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal)
   if (relent->howto->dst_mask != 0
       && (relent->howto->bitsize
 	  != ((unsigned int) internal->r_size & 0x1f) + 1))
-    abort ();
+    relent->howto = NULL;
 }
 
 reloc_howto_type *
@@ -1236,9 +1237,7 @@  _bfd_xcoff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < sizeof (xcoff_howto_table) / sizeof (xcoff_howto_table[0]);
-       i++)
+  for (i = 0; i < ARRAY_SIZE (xcoff_howto_table); i++)
     if (xcoff_howto_table[i].name != NULL
 	&& strcasecmp (xcoff_howto_table[i].name, r_name) == 0)
       return &xcoff_howto_table[i];
@@ -3768,6 +3767,14 @@  xcoff_ppc_relocate_section (bfd *output_bfd,
 	 the csect including the symbol which it references.  */
       if (rel->r_type == R_REF)
 	continue;
+      if (rel->r_type >= ARRAY_SIZE (xcoff_howto_table))
+	{
+	  /* xgettext:c-format */
+	  _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+			      input_bfd, rel->r_type);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
 
       /* Retrieve default value in HOWTO table and fix up according
 	 to r_size field, if it can be different.
@@ -3787,7 +3794,7 @@  xcoff_ppc_relocate_section (bfd *output_bfd,
 
 	    default:
 	      _bfd_error_handler
-		(_("%pB: relocation (%d) at 0x%" PRIx64 " has wrong r_rsize (0x%x)\n"),
+		(_("%pB: relocation (%#x) at 0x%" PRIx64 " has wrong r_rsize (0x%x)\n"),
 		 input_bfd, rel->r_type, (uint64_t) rel->r_vaddr, rel->r_size);
 	      return false;
 	    }
@@ -3863,10 +3870,9 @@  xcoff_ppc_relocate_section (bfd *output_bfd,
 	    }
 	}
 
-      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
-	  || !((*xcoff_calculate_relocation[rel->r_type])
-	       (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
-		addend, &relocation, contents, info)))
+      if (!((*xcoff_calculate_relocation[rel->r_type])
+	    (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
+	     addend, &relocation, contents, info)))
 	return false;
 
       /* address */
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index fa1759b5925..f6a60433e62 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -177,8 +177,7 @@  static bool xcoff64_bad_format_hook
 /* Relocation functions */
 static xcoff_reloc_function xcoff64_reloc_type_br;
 
-xcoff_reloc_function *const
-xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
+xcoff_reloc_function *const xcoff64_calculate_relocation[] =
 {
   xcoff_reloc_type_pos,  /* R_POS     (0x00) */
   xcoff_reloc_type_neg,  /* R_NEG     (0x01) */
@@ -1439,8 +1438,11 @@  reloc_howto_type xcoff64_howto_table[] =
 void
 xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
 {
-  if (internal->r_type > R_TOCL)
-    abort ();
+  if (internal->r_type >= ARRAY_SIZE (xcoff64_howto_table))
+    {
+      relent->howto = NULL;
+      return;
+    }
 
   /* Default howto layout works most of the time */
   relent->howto = &xcoff64_howto_table[internal->r_type];
@@ -1473,7 +1475,7 @@  xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
   if (relent->howto->dst_mask != 0
       && (relent->howto->bitsize
 	  != ((unsigned int) internal->r_size & 0x3f) + 1))
-    abort ();
+    relent->howto = NULL;
 }
 
 reloc_howto_type *
@@ -1528,9 +1530,7 @@  xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]);
-       i++)
+  for (i = 0; i < ARRAY_SIZE (xcoff64_howto_table); i++)
     if (xcoff64_howto_table[i].name != NULL
 	&& strcasecmp (xcoff64_howto_table[i].name, r_name) == 0)
       return &xcoff64_howto_table[i];
@@ -1574,6 +1574,14 @@  xcoff64_ppc_relocate_section (bfd *output_bfd,
 	 the csect including the symbol which it references.  */
       if (rel->r_type == R_REF)
 	continue;
+      if (rel->r_type >= ARRAY_SIZE (xcoff64_howto_table))
+	{
+	  /* xgettext:c-format */
+	  _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+			      input_bfd, rel->r_type);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
 
       /* Retrieve default value in HOWTO table and fix up according
 	 to r_size field, if it can be different.
@@ -1595,7 +1603,7 @@  xcoff64_ppc_relocate_section (bfd *output_bfd,
 
 	    default:
 	      _bfd_error_handler
-		(_("%pB: relocation (%d) at (0x%" PRIx64 ") has wrong"
+		(_("%pB: relocation (%#x) at (0x%" PRIx64 ") has wrong"
 		   " r_rsize (0x%x)\n"),
 		 input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
 	      return false;
@@ -1668,10 +1676,9 @@  xcoff64_ppc_relocate_section (bfd *output_bfd,
 	    }
 	}
 
-      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
-	  || !((*xcoff64_calculate_relocation[rel->r_type])
-	      (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
-	       addend, &relocation, contents, info)))
+      if (!((*xcoff64_calculate_relocation[rel->r_type])
+	    (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
+	     addend, &relocation, contents, info)))
 	return false;
 
       /* address */
diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h
index c116d9b795f..e6b87975ff6 100644
--- a/bfd/libxcoff.h
+++ b/bfd/libxcoff.h
@@ -217,9 +217,6 @@  struct xcoff_backend_data_rec
 #define bfd_xcoff_text_align_power(a) ((xcoff_data (a)->text_align_power))
 #define bfd_xcoff_data_align_power(a) ((xcoff_data (a)->data_align_power))
 
-/* xcoff*_ppc_relocate_section macros  */
-#define XCOFF_MAX_CALCULATE_RELOCATION (0x32)
-#define XCOFF_MAX_COMPLAIN_OVERFLOW (4)
 /* N_ONES produces N one bits, without overflowing machine arithmetic.  */
 #ifdef N_ONES
 #undef N_ONES