[binutils-gdb] alpha, rl78, rx: UB in reloc handling
Alan Modra via Binutils-cvs <[email protected]> Tue, 7 Jul 2026 01:13:11 +0000 (GMT)
| Newsgroups | gmane.comp.gnu.binutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=192a958f5725c0f5a0338ceb9de580b540db6adb commit 192a958f5725c0f5a0338ceb9de580b540db6adb Author: Alan Modra <[email protected]> Date: Tue Jul 7 10:08:18 2026 +0930 alpha, rl78, rx: UB in reloc handling This patch avoids undefined behaviour and divide by zero exceptions in some relocation processing. In most cases, unsigned arithmetic is used which has defined overflow characteristics. Arithmetic right shift, division, and modulo operations have more special cases. See the explanation in commit 30200464e9dd. * coff-alpha.c (alpha_ecoff_get_relocated_section_contents): Avoid UB in RSHIFT reloc. (alpha_relocate_section): Likewise. * elf32-rl78.c (rl78_compute_complex_reloc): Avoid UB in reloc arithmetic. * elf32-rx.c (rx_elf_relocate_section): Likewise. (rx_offset_for_reloc): Likewise. Diff: --- bfd/coff-alpha.c | 10 +++++-- bfd/elf32-rl78.c | 36 +++++++++++++++++--------- bfd/elf32-rx.c | 79 +++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 93 insertions(+), 32 deletions(-) diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c index 35677e9a933..f0823cdcaa9 100644 --- a/bfd/coff-alpha.c +++ b/bfd/coff-alpha.c @@ -1128,7 +1128,10 @@ alpha_ecoff_get_relocated_section_contents (bfd *abfd, break; } - stack[tos - 1] >>= relocation; + if (relocation >= 64) + stack[tos - 1] = 0; + else + stack[tos - 1] >>= relocation; } break; @@ -1755,7 +1758,10 @@ alpha_relocate_section (bfd *output_bfd, r = bfd_reloc_notsupported; break; } - stack[tos - 1] >>= addend; + if (addend >= 64) + stack[tos - 1] = 0; + else + stack[tos - 1] >>= addend; break; } } diff --git a/bfd/elf32-rl78.c b/bfd/elf32-rl78.c index 2b782c1463a..e9e047fcca7 100644 --- a/bfd/elf32-rl78.c +++ b/bfd/elf32-rl78.c @@ -442,14 +442,14 @@ rl78_compute_complex_reloc (unsigned long r_type, case R_RL78_OPneg: tmp1 = rl78_stack_pop (&status); - tmp1 = - tmp1; + tmp1 = -(uint32_t) tmp1; rl78_stack_push (tmp1, &status); break; case R_RL78_OPadd: tmp2 = rl78_stack_pop (&status); tmp1 = rl78_stack_pop (&status); - tmp1 += tmp2; + tmp1 += (uint32_t) tmp2; rl78_stack_push (tmp1, &status); break; @@ -458,41 +458,51 @@ rl78_compute_complex_reloc (unsigned long r_type, then B, then OPSUB. So the first op we pop is B, not A. */ tmp2 = rl78_stack_pop (&status); /* B */ tmp1 = rl78_stack_pop (&status); /* A */ - tmp1 -= tmp2; /* A - B */ + tmp1 -= (uint32_t) tmp2; /* A - B */ rl78_stack_push (tmp1, &status); break; case R_RL78_OPmul: tmp2 = rl78_stack_pop (&status); tmp1 = rl78_stack_pop (&status); - tmp1 *= tmp2; + tmp1 *= (uint32_t) tmp2; rl78_stack_push (tmp1, &status); break; case R_RL78_OPdiv: tmp2 = rl78_stack_pop (&status); tmp1 = rl78_stack_pop (&status); - if (tmp2 != 0) - tmp1 /= tmp2; - else + if (tmp2 == 0) { tmp1 = 0; status = bfd_reloc_overflow; } + else if (tmp2 == 1) + ; + else if (tmp2 == -1) + tmp1 = -(uint32_t) tmp1; + else + tmp1 /= tmp2; rl78_stack_push (tmp1, &status); break; case R_RL78_OPshla: tmp2 = rl78_stack_pop (&status); tmp1 = rl78_stack_pop (&status); - tmp1 <<= tmp2; + if ((uint32_t) tmp2 >= 32) + tmp1 = 0; + else + tmp1 = (uint32_t) tmp1 << tmp2; rl78_stack_push (tmp1, &status); break; case R_RL78_OPshra: tmp2 = rl78_stack_pop (&status); tmp1 = rl78_stack_pop (&status); - tmp1 >>= tmp2; + if ((uint32_t) tmp2 >= 31) + tmp1 = tmp1 < 0 ? -1 : 1; + else + tmp1 >>= tmp2; rl78_stack_push (tmp1, &status); break; @@ -534,13 +544,15 @@ rl78_compute_complex_reloc (unsigned long r_type, case R_RL78_OPmod: tmp2 = rl78_stack_pop (&status); tmp1 = rl78_stack_pop (&status); - if (tmp2 != 0) - tmp1 %= tmp2; - else + if (tmp2 == 0) { tmp1 = 0; status = bfd_reloc_overflow; } + else if (tmp2 == 1 || tmp2 == -1) + tmp1 = 0; + else + tmp1 %= tmp2; rl78_stack_push (tmp1, &status); break; } diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c index 1421e443e51..68eb99fd392 100644 --- a/bfd/elf32-rx.c +++ b/bfd/elf32-rx.c @@ -1308,7 +1308,7 @@ rx_elf_relocate_section case R_RX_OPneg: { - int32_t tmp; + uint32_t tmp; saw_subtract = true; RX_STACK_POP (tmp); @@ -1319,7 +1319,7 @@ rx_elf_relocate_section case R_RX_OPadd: { - int32_t tmp1, tmp2; + uint32_t tmp1, tmp2; RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); @@ -1330,7 +1330,7 @@ rx_elf_relocate_section case R_RX_OPsub: { - int32_t tmp1, tmp2; + uint32_t tmp1, tmp2; saw_subtract = true; RX_STACK_POP (tmp1); @@ -1342,7 +1342,7 @@ rx_elf_relocate_section case R_RX_OPmul: { - int32_t tmp1, tmp2; + uint32_t tmp1, tmp2; RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); @@ -1357,29 +1357,46 @@ rx_elf_relocate_section RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 /= tmp2; + if (tmp2 == 0) + { + tmp1 = 0; + r = bfd_reloc_overflow; + } + else if (tmp2 == 1) + ; + else if (tmp2 == -1) + tmp1 = - (uint32_t) tmp1; + else + tmp1 /= tmp2; RX_STACK_PUSH (tmp1); } break; case R_RX_OPshla: { - int32_t tmp1, tmp2; + uint32_t tmp1, tmp2; RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 <<= tmp2; + if (tmp2 >= 32) + tmp1 = 0; + else + tmp1 <<= tmp2; RX_STACK_PUSH (tmp1); } break; case R_RX_OPshra: { - int32_t tmp1, tmp2; + int32_t tmp1; + uint32_t tmp2; RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 >>= tmp2; + if (tmp2 >= 31) + tmp1 = tmp1 < 0 ? -1 : 1; + else + tmp1 >>= tmp2; RX_STACK_PUSH (tmp1); } break; @@ -1441,7 +1458,15 @@ rx_elf_relocate_section RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 %= tmp2; + if (tmp2 == 0) + { + tmp1 = 0; + r = bfd_reloc_overflow; + } + else if (tmp2 == 1 || tmp2 == -1) + tmp1 = 0; + else + tmp1 %= tmp2; RX_STACK_PUSH (tmp1); } break; @@ -1853,49 +1878,62 @@ rx_offset_for_reloc (bfd * abfd, case R_RX_OPneg: RX_STACK_POP (tmp1); - tmp1 = - tmp1; + tmp1 = - (uint32_t) tmp1; RX_STACK_PUSH (tmp1); break; case R_RX_OPadd: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 += tmp2; + tmp1 += (uint32_t) tmp2; RX_STACK_PUSH (tmp1); break; case R_RX_OPsub: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp2 -= tmp1; + tmp2 -= (uint32_t) tmp1; RX_STACK_PUSH (tmp2); break; case R_RX_OPmul: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 *= tmp2; + tmp1 *= (uint32_t) tmp2; RX_STACK_PUSH (tmp1); break; case R_RX_OPdiv: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 /= tmp2; + if (tmp2 == 0) + tmp1 = 0; + else if (tmp2 == 1) + ; + else if (tmp2 == -1) + tmp1 = - (uint32_t) tmp1; + else + tmp1 /= tmp2; RX_STACK_PUSH (tmp1); break; case R_RX_OPshla: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 <<= tmp2; + if ((uint32_t) tmp2 >= 32) + tmp1 = 0; + else + tmp1 = (uint32_t) tmp1 << tmp2; RX_STACK_PUSH (tmp1); break; case R_RX_OPshra: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 >>= tmp2; + if ((uint32_t) tmp2 >= 31) + tmp1 = tmp1 < 0 ? -1 : 1; + else + tmp1 >>= tmp2; RX_STACK_PUSH (tmp1); break; @@ -1937,7 +1975,12 @@ rx_offset_for_reloc (bfd * abfd, case R_RX_OPmod: RX_STACK_POP (tmp1); RX_STACK_POP (tmp2); - tmp1 %= tmp2; + if (tmp2 == 0) + tmp1 = 0; + else if (tmp2 == -1 || tmp2 == 1) + tmp1 = 0; + else + tmp1 %= tmp2; RX_STACK_PUSH (tmp1); break;