From 066c738ec5d803a080e3da3b0936484a10c8f31b Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 4 Aug 2023 17:37:12 +0930 Subject: [PATCH] ppc: sanity check writing relocs Check for output buffer overruns. * elf32-ppc.c (swap_reloc_out, count_and_swap_reloc_out): New functions. Use throughout file. * elf64-ppc.c (swap_reloc_out, count_and_swap_reloc_out): Likewise. --- bfd/elf32-ppc.c | 63 ++++++++++++++++++++++++++------------------ bfd/elf64-ppc.c | 70 ++++++++++++++++++++++++------------------------- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 37bfbcfc3ba..ccee076555f 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -6935,6 +6935,23 @@ is_insn_dq_form (unsigned int insn) && (insn & 3) == 1)); } +static bool +swap_reloc_out (bfd *obfd, Elf_Internal_Rela *rel, bfd_byte *loc, asection *s) +{ + if ((size_t) (loc - s->contents) >= s->size) + return false; + bfd_elf32_swap_reloca_out (obfd, rel, loc); + return true; +} + +static bool +count_and_swap_reloc_out (bfd *obfd, Elf_Internal_Rela *rel, asection *s) +{ + bfd_byte *loc = s->contents; + loc += s->reloc_count++ * sizeof (Elf32_External_Rela); + return swap_reloc_out (obfd, rel, loc, s); +} + /* The RELOCATE_SECTION function is called by the ELF backend linker to handle the relocations for a section. @@ -7806,7 +7823,6 @@ ppc_elf_relocate_section (bfd *output_bfd, : sym->st_shndx != SHN_ABS))) { asection *rsec = htab->elf.srelgot; - bfd_byte * loc; if (ifunc != NULL) { @@ -7825,11 +7841,9 @@ ppc_elf_relocate_section (bfd *output_bfd, outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32); if (tls_ty == (TLS_TLS | TLS_GD)) { - loc = rsec->contents; - loc += (rsec->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, - &outrel, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, + &outrel, + rsec)); outrel.r_offset += 4; outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32); @@ -7856,10 +7870,8 @@ ppc_elf_relocate_section (bfd *output_bfd, outrel.r_addend -= htab->elf.tls_sec->vma; } } - loc = rsec->contents; - loc += (rsec->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, + &outrel, rsec)); } /* Init the .got section contents if we're not @@ -8089,7 +8101,6 @@ ppc_elf_relocate_section (bfd *output_bfd, && h->dyn_relocs != NULL)) { int skip; - bfd_byte *loc; asection *sreloc; long indx = 0; @@ -8221,9 +8232,8 @@ ppc_elf_relocate_section (bfd *output_bfd, if (sreloc == NULL) return false; - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, &outrel, + sreloc)); if (skip == -1) goto copy_reloc; @@ -9573,7 +9583,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); rela.r_addend = got_offset; - bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (info->output_bfd, &rela, loc, + htab->srelplt2)); loc += sizeof (Elf32_External_Rela); /* Provide the @l relocation for the second instruction. */ @@ -9583,7 +9594,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); rela.r_addend = got_offset; - bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (info->output_bfd, &rela, loc, + htab->srelplt2)); loc += sizeof (Elf32_External_Rela); /* Provide a relocation for the GOT entry corresponding to this @@ -9594,7 +9606,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_PPC_ADDR32); rela.r_addend = ent->plt.offset + 16; - bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (info->output_bfd, &rela, loc, + htab->srelplt2)); } /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. @@ -9676,7 +9689,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf) if (h->type == STT_GNU_IFUNC && is_static_defined (h)) htab->maybe_local_ifunc_resolver = 1; } - bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (info->output_bfd, &rela, + loc, relplt)); } doneone = true; } @@ -9793,9 +9807,8 @@ ppc_finish_symbols (struct bfd_link_info *info) + plt->output_offset + plt->output_section->vma); rela.r_addend = val; - loc = relplt->contents + (relplt->reloc_count++ - * sizeof (Elf32_External_Rela)); - bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (count_and_swap_reloc_out (info->output_bfd, &rela, + relplt)); p = (unsigned char *) htab->glink->contents + ent->glink_offset; write_glink_stub (NULL, ent, htab->elf.iplt, p, info); @@ -9879,7 +9892,6 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, { asection *s; Elf_Internal_Rela rela; - bfd_byte *loc; /* This symbols needs a copy reloc. Set it up. */ @@ -9900,8 +9912,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, rela.r_offset = SYM_VAL (h); rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); rela.r_addend = 0; - loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, &rela, s)); } #ifdef DEBUG @@ -10105,7 +10116,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + 2); rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); rela.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (output_bfd, &rela, loc, htab->srelplt2)); loc += sizeof (Elf32_External_Rela); /* Output the @l relocation for the second instruction. */ @@ -10114,7 +10125,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + 6); rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); rela.r_addend = 0; - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (output_bfd, &rela, loc, htab->srelplt2)); loc += sizeof (Elf32_External_Rela); /* Fix up the remaining relocations. They may have the wrong diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index dea9408ca49..744e4d0ef1e 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -11569,6 +11569,24 @@ get_relocs (asection *sec, int count) return relocs; } +static bool +swap_reloc_out (bfd *obfd, Elf_Internal_Rela *rel, bfd_byte *loc, asection *s) +{ + if ((size_t) (loc - s->contents) >= s->size) + return false; + bfd_elf64_swap_reloca_out (obfd, rel, loc); + return true; +} + +static bool +count_and_swap_reloc_out (bfd *obfd, Elf_Internal_Rela *rel, asection *s) +{ + bfd_byte *loc = s->contents; + loc += s->reloc_count++ * sizeof (Elf64_External_Rela); + return swap_reloc_out (obfd, rel, loc, s); +} + + /* Convert the relocs R[0] thru R[-NUM_REL+1], which are all no-symbol forms, to the equivalent relocs against the global symbol given by STUB_ENTRY->H. */ @@ -11847,7 +11865,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) { /* Create a reloc for the branch lookup table entry. */ Elf_Internal_Rela rela; - bfd_byte *rl; rela.r_offset = (br_entry->offset + htab->brlt->output_offset @@ -11855,10 +11872,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); rela.r_addend = targ; - rl = htab->relbrlt->contents; - rl += (htab->relbrlt->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl); + BFD_ASSERT (count_and_swap_reloc_out (htab->relbrlt->owner, &rela, + htab->relbrlt)); } else if (info->emitrelocations) { @@ -14652,9 +14667,8 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) rela.r_offset = (plt->output_section->vma + plt->output_offset + ent->plt.offset); - loc = relplt->contents + (relplt->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (count_and_swap_reloc_out (info->output_bfd, &rela, + relplt)); } } else @@ -14669,7 +14683,8 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf) / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); if (h->type == STT_GNU_IFUNC && is_static_defined (h)) htab->elf.ifunc_resolvers = true; - bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (swap_reloc_out (info->output_bfd, &rela, + loc, htab->elf.srelplt)); } } @@ -14790,7 +14805,6 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) Elf_Internal_Sym *sym; asection *sym_sec; asection *plt, *relplt; - bfd_byte *loc; bfd_vma val; if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms, @@ -14822,7 +14836,7 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) if (relplt == NULL) { - loc = plt->contents + ent->plt.offset; + bfd_byte *loc = plt->contents + ent->plt.offset; bfd_put_64 (info->output_bfd, val, loc); if (htab->opd_abi) { @@ -14851,9 +14865,8 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info) rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); } rela.r_addend = val; - loc = relplt->contents + (relplt->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc); + BFD_ASSERT (count_and_swap_reloc_out (info->output_bfd, + &rela, relplt)); } } @@ -16991,11 +17004,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64); if (tls_type == (TLS_TLS | TLS_GD)) { - loc = relgot->contents; - loc += (relgot->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (output_bfd, - &outrel, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, + &outrel, + relgot)); outrel.r_offset += 8; outrel.r_addend = orig_rel.r_addend; outrel.r_info @@ -17035,12 +17046,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, } if (!(info->enable_dt_relr && ELF64_R_TYPE (outrel.r_info) == R_PPC64_RELATIVE)) - { - loc = relgot->contents; - loc += (relgot->reloc_count++ - * sizeof (Elf64_External_Rela)); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); - } + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, + &outrel, relgot)); } /* Init the .got section contents here if we're not @@ -17526,12 +17533,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (sreloc == NULL) abort (); - if (sreloc->reloc_count * sizeof (Elf64_External_Rela) - >= sreloc->size) - abort (); - loc = sreloc->contents; - loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, &outrel, + sreloc)); } if (!warned_dynamic @@ -18164,7 +18167,6 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, /* This symbol needs a copy reloc. Set it up. */ Elf_Internal_Rela rela; asection *srel; - bfd_byte *loc; if (h->dynindx == -1) abort (); @@ -18176,9 +18178,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, srel = htab->elf.sreldynrelro; else srel = htab->elf.srelbss; - loc = srel->contents; - loc += srel->reloc_count++ * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); + BFD_ASSERT (count_and_swap_reloc_out (output_bfd, &rela, srel)); } return true;