From 4b738eecc008099574fb8263b2e1fac758eedf02 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 30 Oct 2025 16:26:57 +1030 Subject: [PATCH] Sanity check elf_sym_hashes indexing I'm a little surprised we haven't already had fuzzing reports of indexing off the end of sym_hashes. The idea here is to preempt such bugs. One wrinkle is that ppc64 can't leave a zero symtab_hdr when setting up sym_hashes for the fake stub bfd. * elf-bfd.h (struct elf_reloc_cookie): Add "num_sym". (_bfd_elf_get_link_hash_entry): Update declaration. * elf-eh-frame.c (find_merged_cie): Sanity check reloc symbol index. * elf64-ppc.c (use_global_in_relocs): Fake up symtab_hdr for stub bfd. * elflink.c (_bfd_elf_get_link_hash_entry): Add "num_sym" param. Check symndx against it. Update all calls. (set_symbol_value): Add "num_sym" param and update all calls. (elf_link_input_bfd): Add "num_syms" var and use for above. (init_reloc_cookie): Set "cookie->num_syms". * elf64-x86-64.c (elf_x86_64_scan_relocs): Pass symtab number of entries to _bfd_elf_get_link_hash_entry. * elfxx-x86.c (_bfd_x86_elf_check_relocs): Likewise. (_bfd_x86_elf_link_relax_section): Likewise. --- bfd/elf-bfd.h | 4 +++- bfd/elf-eh-frame.c | 2 ++ bfd/elf64-ppc.c | 3 +++ bfd/elf64-x86-64.c | 3 ++- bfd/elflink.c | 28 +++++++++++++++++----------- bfd/elfxx-x86.c | 6 ++++-- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index e51bfcf6360..372203dd33c 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -901,6 +901,8 @@ struct elf_reloc_cookie { bfd *abfd; Elf_Internal_Rela *rels, *rel, *relend; + /* Number of symbols in .symtab. */ + unsigned int num_sym; /* Number of symbols that may be local syms (all when bad_symtab). */ unsigned int locsymcount; /* Symbol index of first possible global sym (0 when bad_symtab). */ @@ -3172,7 +3174,7 @@ extern void _bfd_elf_link_munmap_section_contents (asection *); extern struct elf_link_hash_entry * _bfd_elf_get_link_hash_entry - (struct elf_link_hash_entry **, unsigned int, unsigned int); + (struct elf_link_hash_entry **, unsigned int, unsigned int, unsigned int); extern asection *_bfd_get_local_sym_section (struct elf_reloc_cookie *, unsigned int); diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 97ba1a3dce6..0212523cc79 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -1256,6 +1256,8 @@ find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec, #endif r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx > cookie->num_sym) + return cie_inf; h = NULL; if (r_symndx >= cookie->extsymoff) h = elf_sym_hashes (cookie->abfd)[r_symndx - cookie->extsymoff]; diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index b706cf4d438..205cf1511cb 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -11641,6 +11641,9 @@ use_global_in_relocs (struct ppc_link_hash_table *htab, if (hashes == NULL) return false; elf_sym_hashes (htab->params->stub_bfd) = hashes; + Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (htab->params->stub_bfd); + symtab_hdr->sh_entsize = sizeof (Elf64_External_Sym); + symtab_hdr->sh_size = (htab->stub_globals + 1) * symtab_hdr->sh_entsize; htab->stub_globals = 1; } symndx = htab->stub_globals++; diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index f2a172662a5..a4a5ebf595e 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -2616,7 +2616,8 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, { isym = NULL; h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, - symtab_hdr->sh_info); + symtab_hdr->sh_info, + NUM_SHDR_ENTRIES (symtab_hdr)); } /* Check invalid x32 relocations. */ diff --git a/bfd/elflink.c b/bfd/elflink.c index 989a7a0a6af..0ea974d45ce 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -96,11 +96,13 @@ _bfd_elf_link_keep_memory (struct bfd_link_info *info) struct elf_link_hash_entry * _bfd_elf_get_link_hash_entry (struct elf_link_hash_entry **sym_hashes, unsigned int symndx, - unsigned int ext_sym_start) + unsigned int ext_sym_start, + unsigned int num_sym) { if (sym_hashes == NULL /* Guard against corrupt input. See PR 32636 for an example. */ - || symndx < ext_sym_start) + || symndx < ext_sym_start + || symndx >= num_sym) return NULL; struct elf_link_hash_entry *h = sym_hashes[symndx - ext_sym_start]; @@ -124,7 +126,7 @@ get_ext_sym_hash_from_cookie (struct elf_reloc_cookie *cookie, return NULL; return _bfd_elf_get_link_hash_entry (elf_sym_hashes (cookie->abfd), symndx, - cookie->extsymoff); + cookie->extsymoff, cookie->num_sym); } asection * @@ -9108,6 +9110,7 @@ static bool set_symbol_value (bfd *bfd_with_globals, Elf_Internal_Sym *isymbuf, size_t locsymcount, + size_t num_sym, size_t symidx, bfd_vma val) { @@ -9140,7 +9143,7 @@ set_symbol_value (bfd *bfd_with_globals, /* It is a global symbol: set its link type to "defined" and give it a value. */ h = _bfd_elf_get_link_hash_entry (elf_sym_hashes (bfd_with_globals), symidx, - extsymoff); + extsymoff, num_sym); if (h == NULL) return false; h->root.type = bfd_link_hash_defined; @@ -11355,6 +11358,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) Elf_Internal_Shdr *symtab_hdr; size_t locsymcount; size_t extsymoff; + size_t num_sym; Elf_Internal_Sym *isymbuf; Elf_Internal_Sym *isym; Elf_Internal_Sym *isymend; @@ -11379,9 +11383,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) return true; symtab_hdr = &elf_symtab_hdr (input_bfd); + num_sym = symtab_hdr->sh_size / bed->s->sizeof_sym; if (elf_bad_symtab (input_bfd)) { - locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; + locsymcount = num_sym; extsymoff = 0; } else @@ -11622,7 +11627,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) struct elf_link_hash_entry *h; h = _bfd_elf_get_link_hash_entry (sym_hashes, symndx, - extsymoff); + extsymoff, num_sym); if (h == NULL) { _bfd_error_handler @@ -11768,7 +11773,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) && flinfo->sections[r_symndx] == NULL)) { h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, - extsymoff); + extsymoff, num_sym); /* Badly formatted input files can contain relocs that reference non-existant symbols. Check here so that @@ -11844,8 +11849,8 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) return false; /* Symbol evaluated OK. Update to absolute value. */ - if (!set_symbol_value (input_bfd, isymbuf, locsymcount, r_symndx, - val)) + if (!set_symbol_value (input_bfd, isymbuf, locsymcount, + num_sym, r_symndx, val)) return false; continue; @@ -12010,7 +12015,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) for this symbol. The symbol index is then set at the end of bfd_elf_final_link. */ rh = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, - extsymoff); + extsymoff, num_sym); if (rh == NULL) { /* FIXME: Generate an error ? */ @@ -13841,9 +13846,10 @@ init_reloc_cookie (struct elf_reloc_cookie *cookie, bfd *abfd) symtab_hdr = &elf_tdata (abfd)->symtab_hdr; cookie->abfd = abfd; + cookie->num_sym = symtab_hdr->sh_size / bed->s->sizeof_sym; if (elf_bad_symtab (abfd)) { - cookie->locsymcount = symtab_hdr->sh_size / bed->s->sizeof_sym; + cookie->locsymcount = cookie->num_sym; cookie->extsymoff = 0; } else diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index cffec0f5aab..7a54722bd27 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -967,7 +967,8 @@ _bfd_x86_elf_check_relocs (bfd *abfd, } h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, - symtab_hdr->sh_info); + symtab_hdr->sh_info, + NUM_SHDR_ENTRIES (symtab_hdr)); if (X86_NEED_DYNAMIC_RELOC_TYPE_P (is_x86_64, r_type) && NEED_DYNAMIC_RELOCATION_P (is_x86_64, info, true, h, sec, @@ -1196,7 +1197,8 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED, { /* Get H and SEC for GENERATE_DYNAMIC_RELOCATION_P below. */ h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, - symtab_hdr->sh_info); + symtab_hdr->sh_info, + NUM_SHDR_ENTRIES (symtab_hdr)); if (h == NULL) { /* FIXMEL: Issue an error message ? */ -- 2.47.3