Backported of:

From 18cc11a2771d9e40180485da9a4fb660c03efac3 Mon Sep 17 00:00:00 2001
From: Nick Clifton <nickc@redhat.com>
Date: Wed, 5 Feb 2025 14:31:10 +0000
Subject: [PATCH] Prevent illegal memory access when checking relocs in a
 corrupt ELF binary.

PR 32641

Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/binutils/plain/debian/patches/CVE-2025-1181-pre.patch?h=applied/ubuntu/noble-security&id=d6b5bf57cf048c42e4bcd3a4ab32116d0b809774]
Upstream commit [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=931494c9a89558acb36a03a340c01726545eef24]

CVE: CVE-2025-1181

Signed-off-by: Ashish Sharma <asharma@mvista.com>

 bfd/elf-bfd.h      |  3 +++
 bfd/elf64-x86-64.c | 10 +++++-----
 bfd/elflink.c      | 24 ++++++++++++++++++++++++
 bfd/elfxx-x86.c    | 20 +++++++-------------
 4 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 3ed22fa6..07add7d0 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -3126,6 +3126,9 @@ extern bool _bfd_elf_maybe_set_textrel
 extern bool _bfd_elf_add_dynamic_tags
   (bfd *, struct bfd_link_info *, bool);
 
+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 d0d3b0e5..c3fb375c 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1665,7 +1665,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;
@@ -1831,6 +1831,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)
@@ -2127,10 +2130,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 11ec6bd9..e5521d7b 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -49,6 +49,27 @@ struct elf_info_failed
 static bool _bfd_elf_fix_symbol_flags
   (struct elf_link_hash_entry *, struct elf_info_failed *);
 
+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)
 {
@@ -62,6 +83,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 508fd771..8c261cf8 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -972,15 +972,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,
@@ -1205,10 +1197,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)
