]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Sanity check elf_sym_hashes indexing
authorAlan Modra <amodra@gmail.com>
Thu, 30 Oct 2025 05:56:57 +0000 (16:26 +1030)
committerAlan Modra <amodra@gmail.com>
Thu, 30 Oct 2025 05:56:57 +0000 (16:26 +1030)
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
bfd/elf-eh-frame.c
bfd/elf64-ppc.c
bfd/elf64-x86-64.c
bfd/elflink.c
bfd/elfxx-x86.c

index e51bfcf63603ee9f613583cbb00252f43deb5255..372203dd33cbd7296261326b771ac84ee8052b88 100644 (file)
@@ -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);
 
index 97ba1a3dce69db0210541b82b17c15be062abf91..0212523cc79d36f15a23435462def52344468742 100644 (file)
@@ -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];
index b706cf4d438c36576cda47d0fdefadf448fca9b7..205cf1511cbb68a709167ac80452043ad17c32cd 100644 (file)
@@ -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++;
index f2a172662a524e4bdf6600927bec2610aaf649a5..a4a5ebf595e7092d30fb9431a621741aa5f21e2d 100644 (file)
@@ -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.  */
index 989a7a0a6afec7bf8a6202313de61ba0b656044f..0ea974d45ce5e62b4eb41570b2b6611e25b8195f 100644 (file)
@@ -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
index cffec0f5aaba5817bcc332a7a531b3b33f3f529d..7a54722bd27535aa8eca11cc7d6950c887a8b4f1 100644 (file)
@@ -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 ?  */