|
| 1 | +Description: Fix out-of-bounds read in XCOFF relocation processing |
| 2 | + A flaw was found in the GNU Binutils BFD library when processing XCOFF object |
| 3 | + files. The relocation type value is not properly validated before being used, |
| 4 | + which can cause the program to read memory outside of intended bounds. |
| 5 | + . |
| 6 | + This fix adds proper validation of reloc r_type before accessing |
| 7 | + xcoff_howto_table to prevent out-of-bounds memory access. |
| 8 | +Author: Alan Modra <amodra@gmail.com> |
| 9 | +Origin: upstream, https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=9e99dbc1f19ffaf18d0250788951706066ebe7f2 |
| 10 | +Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33919 |
| 11 | +Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2026-4647 |
| 12 | +Forwarded: not-needed |
| 13 | +Last-Update: 2026-04-15 |
| 14 | + |
| 15 | +From 9e99dbc1f19ffaf18d0250788951706066ebe7f2 Mon Sep 17 00:00:00 2001 |
| 16 | +From: Alan Modra <amodra@gmail.com> |
| 17 | +Date: Fri, 13 Mar 2026 17:28:28 +1030 |
| 18 | +Subject: [PATCH] PR33919 Out-of-bounds read in XCOFF relocation processing |
| 19 | + |
| 20 | + PR 33919 |
| 21 | + * coff-rs6000.c (xcoff_calculate_relocation): Don't use explicit |
| 22 | + array size. |
| 23 | + (xcoff_complain_overflow): Likewise. |
| 24 | + (xcoff_rtype2howto): Return a NULL howto rather than aborting. |
| 25 | + (_bfd_xcoff_reloc_name_lookup): Use ARRAY_SIZE. |
| 26 | + (xcoff_ppc_relocate_section): Sanity check reloc r_type before |
| 27 | + accessing xcoff_howto_table. Print r_type using %#x. Remove |
| 28 | + now redundant later reloc r_type sanity check. |
| 29 | + * coff64-rs6000.c: Similarly. |
| 30 | + * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Don't define. |
| 31 | + (XCOFF_MAX_COMPLAIN_OVERFLOW): Don't define. |
| 32 | +--- |
| 33 | + bfd/coff-rs6000.c | 36 +++++++++++++++++++++--------------- |
| 34 | + bfd/coff64-rs6000.c | 33 ++++++++++++++++++++------------- |
| 35 | + bfd/libxcoff.h | 3 --- |
| 36 | + 3 files changed, 41 insertions(+), 31 deletions(-) |
| 37 | + |
| 38 | +diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c |
| 39 | +index 62caae64f4e..00e0f5442f7 100644 |
| 40 | +--- a/bfd/coff-rs6000.c |
| 41 | ++++ b/bfd/coff-rs6000.c |
| 42 | +@@ -155,8 +155,7 @@ static xcoff_complain_function xcoff_complain_overflow_bitfield_func; |
| 43 | + static xcoff_complain_function xcoff_complain_overflow_signed_func; |
| 44 | + static xcoff_complain_function xcoff_complain_overflow_unsigned_func; |
| 45 | + |
| 46 | +-xcoff_reloc_function *const |
| 47 | +-xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = |
| 48 | ++xcoff_reloc_function *const xcoff_calculate_relocation[] = |
| 49 | + { |
| 50 | + xcoff_reloc_type_pos, /* R_POS (0x00) */ |
| 51 | + xcoff_reloc_type_neg, /* R_NEG (0x01) */ |
| 52 | +@@ -210,8 +209,7 @@ xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = |
| 53 | + xcoff_reloc_type_toc, /* R_TOCL (0x31) */ |
| 54 | + }; |
| 55 | + |
| 56 | +-xcoff_complain_function *const |
| 57 | +-xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW] = |
| 58 | ++xcoff_complain_function *const xcoff_complain_overflow[] = |
| 59 | + { |
| 60 | + xcoff_complain_overflow_dont_func, |
| 61 | + xcoff_complain_overflow_bitfield_func, |
| 62 | +@@ -1158,8 +1156,11 @@ reloc_howto_type xcoff_howto_table[] = |
| 63 | + void |
| 64 | + xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal) |
| 65 | + { |
| 66 | +- if (internal->r_type > R_TOCL) |
| 67 | +- abort (); |
| 68 | ++ if (internal->r_type >= ARRAY_SIZE (xcoff_howto_table)) |
| 69 | ++ { |
| 70 | ++ relent->howto = NULL; |
| 71 | ++ return; |
| 72 | ++ } |
| 73 | + |
| 74 | + /* Default howto layout works most of the time */ |
| 75 | + relent->howto = &xcoff_howto_table[internal->r_type]; |
| 76 | +@@ -1183,7 +1184,7 @@ xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal) |
| 77 | + if (relent->howto->dst_mask != 0 |
| 78 | + && (relent->howto->bitsize |
| 79 | + != ((unsigned int) internal->r_size & 0x1f) + 1)) |
| 80 | +- abort (); |
| 81 | ++ relent->howto = NULL; |
| 82 | + } |
| 83 | + |
| 84 | + reloc_howto_type * |
| 85 | +@@ -1236,9 +1237,7 @@ _bfd_xcoff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| 86 | + { |
| 87 | + unsigned int i; |
| 88 | + |
| 89 | +- for (i = 0; |
| 90 | +- i < sizeof (xcoff_howto_table) / sizeof (xcoff_howto_table[0]); |
| 91 | +- i++) |
| 92 | ++ for (i = 0; i < ARRAY_SIZE (xcoff_howto_table); i++) |
| 93 | + if (xcoff_howto_table[i].name != NULL |
| 94 | + && strcasecmp (xcoff_howto_table[i].name, r_name) == 0) |
| 95 | + return &xcoff_howto_table[i]; |
| 96 | +@@ -3768,6 +3767,14 @@ xcoff_ppc_relocate_section (bfd *output_bfd, |
| 97 | + the csect including the symbol which it references. */ |
| 98 | + if (rel->r_type == R_REF) |
| 99 | + continue; |
| 100 | ++ if (rel->r_type >= ARRAY_SIZE (xcoff_howto_table)) |
| 101 | ++ { |
| 102 | ++ /* xgettext:c-format */ |
| 103 | ++ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), |
| 104 | ++ input_bfd, rel->r_type); |
| 105 | ++ bfd_set_error (bfd_error_bad_value); |
| 106 | ++ return false; |
| 107 | ++ } |
| 108 | + |
| 109 | + /* Retrieve default value in HOWTO table and fix up according |
| 110 | + to r_size field, if it can be different. |
| 111 | +@@ -3787,7 +3794,7 @@ xcoff_ppc_relocate_section (bfd *output_bfd, |
| 112 | + |
| 113 | + default: |
| 114 | + _bfd_error_handler |
| 115 | +- (_("%pB: relocation (%d) at 0x%" PRIx64 " has wrong r_rsize (0x%x)\n"), |
| 116 | ++ (_("%pB: relocation (%#x) at 0x%" PRIx64 " has wrong r_rsize (0x%x)\n"), |
| 117 | + input_bfd, rel->r_type, (uint64_t) rel->r_vaddr, rel->r_size); |
| 118 | + return false; |
| 119 | + } |
| 120 | +@@ -3863,10 +3870,9 @@ xcoff_ppc_relocate_section (bfd *output_bfd, |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | +- if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION |
| 125 | +- || !((*xcoff_calculate_relocation[rel->r_type]) |
| 126 | +- (input_bfd, input_section, output_bfd, rel, sym, &howto, val, |
| 127 | +- addend, &relocation, contents, info))) |
| 128 | ++ if (!((*xcoff_calculate_relocation[rel->r_type]) |
| 129 | ++ (input_bfd, input_section, output_bfd, rel, sym, &howto, val, |
| 130 | ++ addend, &relocation, contents, info))) |
| 131 | + return false; |
| 132 | + |
| 133 | + /* address */ |
| 134 | +diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c |
| 135 | +index fa1759b5925..f6a60433e62 100644 |
| 136 | +--- a/bfd/coff64-rs6000.c |
| 137 | ++++ b/bfd/coff64-rs6000.c |
| 138 | +@@ -177,8 +177,7 @@ static bool xcoff64_bad_format_hook |
| 139 | + /* Relocation functions */ |
| 140 | + static xcoff_reloc_function xcoff64_reloc_type_br; |
| 141 | + |
| 142 | +-xcoff_reloc_function *const |
| 143 | +-xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = |
| 144 | ++xcoff_reloc_function *const xcoff64_calculate_relocation[] = |
| 145 | + { |
| 146 | + xcoff_reloc_type_pos, /* R_POS (0x00) */ |
| 147 | + xcoff_reloc_type_neg, /* R_NEG (0x01) */ |
| 148 | +@@ -1439,8 +1438,11 @@ reloc_howto_type xcoff64_howto_table[] = |
| 149 | + void |
| 150 | + xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal) |
| 151 | + { |
| 152 | +- if (internal->r_type > R_TOCL) |
| 153 | +- abort (); |
| 154 | ++ if (internal->r_type >= ARRAY_SIZE (xcoff64_howto_table)) |
| 155 | ++ { |
| 156 | ++ relent->howto = NULL; |
| 157 | ++ return; |
| 158 | ++ } |
| 159 | + |
| 160 | + /* Default howto layout works most of the time */ |
| 161 | + relent->howto = &xcoff64_howto_table[internal->r_type]; |
| 162 | +@@ -1473,7 +1475,7 @@ xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal) |
| 163 | + if (relent->howto->dst_mask != 0 |
| 164 | + && (relent->howto->bitsize |
| 165 | + != ((unsigned int) internal->r_size & 0x3f) + 1)) |
| 166 | +- abort (); |
| 167 | ++ relent->howto = NULL; |
| 168 | + } |
| 169 | + |
| 170 | + reloc_howto_type * |
| 171 | +@@ -1528,9 +1530,7 @@ xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, |
| 172 | + { |
| 173 | + unsigned int i; |
| 174 | + |
| 175 | +- for (i = 0; |
| 176 | +- i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]); |
| 177 | +- i++) |
| 178 | ++ for (i = 0; i < ARRAY_SIZE (xcoff64_howto_table); i++) |
| 179 | + if (xcoff64_howto_table[i].name != NULL |
| 180 | + && strcasecmp (xcoff64_howto_table[i].name, r_name) == 0) |
| 181 | + return &xcoff64_howto_table[i]; |
| 182 | +@@ -1574,6 +1574,14 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, |
| 183 | + the csect including the symbol which it references. */ |
| 184 | + if (rel->r_type == R_REF) |
| 185 | + continue; |
| 186 | ++ if (rel->r_type >= ARRAY_SIZE (xcoff64_howto_table)) |
| 187 | ++ { |
| 188 | ++ /* xgettext:c-format */ |
| 189 | ++ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), |
| 190 | ++ input_bfd, rel->r_type); |
| 191 | ++ bfd_set_error (bfd_error_bad_value); |
| 192 | ++ return false; |
| 193 | ++ } |
| 194 | + |
| 195 | + /* Retrieve default value in HOWTO table and fix up according |
| 196 | + to r_size field, if it can be different. |
| 197 | +@@ -1595,7 +1603,7 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, |
| 198 | + |
| 199 | + default: |
| 200 | + _bfd_error_handler |
| 201 | +- (_("%pB: relocation (%d) at (0x%" PRIx64 ") has wrong" |
| 202 | ++ (_("%pB: relocation (%#x) at (0x%" PRIx64 ") has wrong" |
| 203 | + " r_rsize (0x%x)\n"), |
| 204 | + input_bfd, rel->r_type, rel->r_vaddr, rel->r_size); |
| 205 | + return false; |
| 206 | +@@ -1668,10 +1676,9 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | +- if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION |
| 211 | +- || !((*xcoff64_calculate_relocation[rel->r_type]) |
| 212 | +- (input_bfd, input_section, output_bfd, rel, sym, &howto, val, |
| 213 | +- addend, &relocation, contents, info))) |
| 214 | ++ if (!((*xcoff64_calculate_relocation[rel->r_type]) |
| 215 | ++ (input_bfd, input_section, output_bfd, rel, sym, &howto, val, |
| 216 | ++ addend, &relocation, contents, info))) |
| 217 | + return false; |
| 218 | + |
| 219 | + /* address */ |
| 220 | +diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h |
| 221 | +index c116d9b795f..e6b87975ff6 100644 |
| 222 | +--- a/bfd/libxcoff.h |
| 223 | ++++ b/bfd/libxcoff.h |
| 224 | +@@ -217,9 +217,6 @@ struct xcoff_backend_data_rec |
| 225 | + #define bfd_xcoff_text_align_power(a) ((xcoff_data (a)->text_align_power)) |
| 226 | + #define bfd_xcoff_data_align_power(a) ((xcoff_data (a)->data_align_power)) |
| 227 | + |
| 228 | +-/* xcoff*_ppc_relocate_section macros */ |
| 229 | +-#define XCOFF_MAX_CALCULATE_RELOCATION (0x32) |
| 230 | +-#define XCOFF_MAX_COMPLAIN_OVERFLOW (4) |
| 231 | + /* N_ONES produces N one bits, without overflowing machine arithmetic. */ |
| 232 | + #ifdef N_ONES |
| 233 | + #undef N_ONES |
| 234 | +-- |
| 235 | +2.43.7 |
| 236 | + |
0 commit comments