[binutils-gdb] PR33919 Out-of-bounds read in XCOFF relocation processing

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=9e99dbc1f19ffaf18d0250788951706066ebe7f2

commit 9e99dbc1f19ffaf18d0250788951706066ebe7f2
Author: Alan Modra <[email protected]>
Date:   Fri Mar 13 17:28:28 2026 +1030

    PR33919 Out-of-bounds read in XCOFF relocation processing
    
            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.

Diff:
---
 bfd/coff-rs6000.c   | 36 +++++++++++++++++++++---------------
 bfd/coff64-rs6000.c | 33 ++++++++++++++++++++-------------
 bfd/libxcoff.h      |  3 ---
 3 files changed, 41 insertions(+), 31 deletions(-)

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
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.