From: Nick Clifton Date: Wed, 5 Feb 2025 14:31:10 +0000 (+0000) Subject: Prevent illegal memory access when checking relocs in a corrupt ELF binary. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=18cc11a2771d9e40180485da9a4fb660c03efac3;p=thirdparty%2Fbinutils-gdb.git Prevent illegal memory access when checking relocs in a corrupt ELF binary. PR 32641 --- diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 785a37dd7fd..d2bf8e5cbae 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -3153,6 +3153,9 @@ extern bool _bfd_elf_link_mmap_section_contents 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, Elf_Internal_Shdr *); + /* Large common section. */ extern asection _bfd_elf_large_com_section; diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 32db254ba6c..2d82c6583c3 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1784,7 +1784,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd, bool to_reloc_pc32; bool abs_symbol; bool local_ref; - asection *tsec; + asection *tsec = NULL; bfd_signed_vma raddend; unsigned int opcode; unsigned int modrm; @@ -1999,6 +1999,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd, return true; } + if (tsec == NULL) + return false; + /* Don't convert GOTPCREL relocation against large section. */ if (elf_section_data (tsec) != NULL && (elf_section_flags (tsec) & SHF_X86_64_LARGE) != 0) @@ -2408,10 +2411,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info, else { isym = NULL; - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, symtab_hdr); } /* Check invalid x32 relocations. */ diff --git a/bfd/elflink.c b/bfd/elflink.c index 1f1263007c0..eafbd133ff5 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -96,6 +96,27 @@ _bfd_elf_link_keep_memory (struct bfd_link_info *info) return true; } +struct elf_link_hash_entry * +_bfd_elf_get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, + unsigned int symndx, + Elf_Internal_Shdr * symtab_hdr) +{ + if (symndx < symtab_hdr->sh_info) + return NULL; + + struct elf_link_hash_entry *h = sym_hashes[symndx - symtab_hdr->sh_info]; + + /* The hash might be empty. See PR 32641 for an example of this. */ + if (h == NULL) + return NULL; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + return h; +} + static struct elf_link_hash_entry * get_ext_sym_hash (struct elf_reloc_cookie *cookie, unsigned long r_symndx) { @@ -108,6 +129,9 @@ get_ext_sym_hash (struct elf_reloc_cookie *cookie, unsigned long r_symndx) { h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; + if (h == NULL) + return NULL; + while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 8e5a005fd36..832a5495eb1 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -973,15 +973,7 @@ _bfd_x86_elf_check_relocs (bfd *abfd, goto error_return; } - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else - { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - } + h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, 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, @@ -1209,10 +1201,12 @@ _bfd_x86_elf_link_relax_section (bfd *abfd ATTRIBUTE_UNUSED, else { /* Get H and SEC for GENERATE_DYNAMIC_RELOCATION_P below. */ - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, symtab_hdr); + if (h == NULL) + { + /* FIXMEL: Issue an error message ? */ + continue; + } if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak)