Sanity check elf_sym_hashes indexing
Alan Modra
amodra@gmail.com
Tue Oct 21 23:48:27 GMT 2025
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.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index e25e2fca2a6..687e699fa80 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -904,6 +904,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). */
@@ -3180,7 +3182,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 77c64e2f729..0c521c09722 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 ca0b41a56d3..bddeab142db 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 *
@@ -9165,6 +9167,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)
{
@@ -9197,7 +9200,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)
{
/* FIXMEL What should we do ? */
@@ -11415,6 +11418,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;
@@ -11439,9 +11443,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
@@ -11684,7 +11689,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
@@ -11830,7 +11835,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
@@ -11906,8 +11911,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;
@@ -12072,7 +12077,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 ? */
@@ -13905,9 +13910,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 ? */
--
Alan Modra
More information about the Binutils
mailing list