[binutils-gdb] x86: Check invalid GOT/PLT/TLS relocations

"H.J. Lu via Binutils-cvs" <[email protected]> Tue, 4 Aug 2026 03:33:46 +0000 (GMT)
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D471130b39c03=
623ec6d78ece377ff4da3f6bfe7b

commit 471130b39c03623ec6d78ece377ff4da3f6bfe7b
Author: H.J. Lu <[email protected]>
Date:   Thu Jul 30 13:43:56 2026 +0800

    x86: Check invalid GOT/PLT/TLS relocations
   =20
    1. Since non-alloc sections aren't checked for TLS, GOT and PLT usages,
    relocate_section should issue error for TLS, GOT and PLT relocations in
    non-alloc and non-debugging sections.
    2. Since TLS relocations must be against thread local symbols, scan_rel=
ocs
    should issue an error for TLS relocation against non-thread local symbo=
l.
   =20
            PR ld/34444
            PR ld/34448
            * elf32-i386.c (elf_i386_tls_transition): Replace
            _bfd_x86_elf_link_report_tls_invalid_section_error with
            _bfd_x86_elf_link_report_error.
            (elf_i386_scan_relocs): Issue an error for TLS relocation again=
st
            non-thread local symbol.
            (elf_i386_relocate_section): Issue error for TLS, GOT and PLT
            relocations in non-alloc and non-debugging sections.
            * elf64-x86-64.c (elf_x86_64_tls_transition): Replace
            _bfd_x86_elf_link_report_tls_invalid_section_error with
            _bfd_x86_elf_link_report_error.
            (elf_x86_64_scan_relocs): Issue an error for TLS relocation
            against non-thread local symbol.
            * elfxx-x86.c (_bfd_x86_elf_link_report_tls_invalid_section_err=
or):
            Renamed to ...
            (_bfd_x86_elf_link_report_error): This.  Add an argument for
            link error type and handle it.
            * elfxx-x86.h (elf_x86_error_type): New enum.
            (_bfd_x86_elf_link_report_tls_invalid_section_error): Renamed
            to ...
            (_bfd_x86_elf_link_report_error): This.  Add an argument of
            enum elf_x86_error_type.
   =20
    Signed-off-by: H.J. Lu <[email protected]>

Diff:
---
 bfd/elf32-i386.c   | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
 bfd/elf64-x86-64.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++--=
---
 bfd/elfxx-x86.c    | 53 ++++++++++++++++++++++++++++++++++++++++++++------=
---
 bfd/elfxx-x86.h    | 11 +++++++++--
 4 files changed, 146 insertions(+), 21 deletions(-)

diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index ae9276cff06..8ad5cb4e354 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1175,8 +1175,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, =
bfd *abfd,
        || (sec->flags & SEC_CODE) =3D=3D 0))
     {
       reloc_howto_type *howto =3D elf_i386_rtype_to_howto (from_type);
-      _bfd_x86_elf_link_report_tls_invalid_section_error
-	(abfd, sec, symtab_hdr, h, sym, howto);
+      _bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr, h, sym,
+				      howto, elf_x86_error_tls);
       return false;
     }
=20
@@ -1749,11 +1749,15 @@ elf_i386_scan_relocs (bfd *abfd,
=20
 	    if (tls_type >=3D GOT_TLS_GD
 		&& tls_type <=3D GOT_TLS_GDESC
-		&& (elf_section_type (sec) !=3D SHT_PROGBITS
+		&& ((h !=3D NULL
+		     ? h->type !=3D STT_TLS
+		     : ELF_ST_TYPE (isym->st_info) !=3D STT_TLS)
+		    || elf_section_type (sec) !=3D SHT_PROGBITS
 		    || (sec->flags & SEC_CODE) =3D=3D 0))
 	      {
-		_bfd_x86_elf_link_report_tls_invalid_section_error
-		  (abfd, sec, symtab_hdr, h, isym, howto);
+		_bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr,
+						h, isym, howto,
+						elf_x86_error_tls);
 		goto error_return;
 	      }
=20
@@ -2585,6 +2589,18 @@ elf_i386_relocate_section (struct bfd_link_info *inf=
o,
 	{
 	case R_386_GOT32X:
 	case R_386_GOT32:
+	  /* Since we don't allow non-alloced sections to create GOT/PLT
+	     entries, issue an error if a non-alloced section references
+	     GOT.  */
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    {
+  non_alloc_error:
+	      _bfd_x86_elf_link_report_error (input_bfd, input_section,
+					      symtab_hdr, h, sym, howto,
+					      elf_x86_error_non_alloc);
+	      return false;
+	    }
+
 	  /* Relocation is to the entry for this symbol in the global
 	     offset table.  */
 	  if (htab->elf.sgot =3D=3D NULL)
@@ -2717,6 +2733,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	  break;
=20
 	case R_386_GOTOFF:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Relocation is relative to the start of the global offset
 	     table.  */
=20
@@ -2781,6 +2800,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	  break;
=20
 	case R_386_GOTPC:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Use global offset table as symbol value.  */
 	  relocation =3D htab->elf.sgotplt->output_section->vma
 		       + htab->elf.sgotplt->output_offset;
@@ -2788,6 +2810,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	  break;
=20
 	case R_386_PLT32:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Relocation is to the entry for this symbol in the
 	     procedure linkage table.  */
=20
@@ -2915,6 +2940,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	  break;
=20
 	case R_386_TLS_IE:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  if (!bfd_link_executable (info))
 	    {
 	      Elf_Internal_Rela outrel;
@@ -2942,6 +2970,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	case R_386_TLS_DESC_CALL:
 	case R_386_TLS_IE_32:
 	case R_386_TLS_GOTIE:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  tls_type =3D GOT_UNKNOWN;
 	  if (h =3D=3D NULL && local_got_offsets)
 	    tls_type =3D elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -3440,6 +3471,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	  break;
=20
 	case R_386_TLS_LDM:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  if (! elf_i386_tls_transition (info, input_bfd,
 					 input_section, contents,
 					 symtab_hdr, sym_hashes,
@@ -3512,6 +3546,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 	  break;
=20
 	case R_386_TLS_LDO_32:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  if (!bfd_link_executable (info)
 	      || (input_section->flags & SEC_CODE) =3D=3D 0)
 	    relocation -=3D _bfd_x86_elf_dtpoff_base (info);
@@ -3522,6 +3559,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
=20
 	case R_386_TLS_LE_32:
 	case R_386_TLS_LE:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  if (!bfd_link_executable (info))
 	    {
 	      Elf_Internal_Rela outrel;
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 3700520b40f..878feb20b85 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1633,8 +1633,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info=
, bfd *abfd,
     {
       reloc_howto_type *howto =3D elf_x86_64_rtype_to_howto (abfd,
 							   from_type);
-      _bfd_x86_elf_link_report_tls_invalid_section_error
-	(abfd, sec, symtab_hdr, h, sym, howto);
+      _bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr, h,
+				      sym, howto, elf_x86_error_tls);
       return false;
     }
=20
@@ -2772,11 +2772,15 @@ need_got:
=20
 	    if (tls_type >=3D GOT_TLS_GD
 		&& tls_type <=3D GOT_TLS_GDESC
-		&& (elf_section_type (sec) !=3D SHT_PROGBITS
+		&& ((h !=3D NULL
+		     ? h->type !=3D STT_TLS
+		     : ELF_ST_TYPE (isym->st_info) !=3D STT_TLS)
+		    || elf_section_type (sec) !=3D SHT_PROGBITS
 		    || (sec->flags & SEC_CODE) =3D=3D 0))
 	      {
-		_bfd_x86_elf_link_report_tls_invalid_section_error
-		  (abfd, sec, symtab_hdr, h, isym, howto);
+		_bfd_x86_elf_link_report_error (abfd, sec, symtab_hdr,
+						h, isym, howto,
+						elf_x86_error_tls);
 		goto error_return;
 	      }
=20
@@ -3602,6 +3606,18 @@ elf_x86_64_relocate_section (struct bfd_link_info *i=
nfo,
 	case R_X86_64_GOTPCREL64:
 	  /* Use global offset table entry as symbol value.  */
 	case R_X86_64_GOTPLT64:
+	  /* Since we don't allow non-alloced sections to create GOT/PLT
+	     entries, issue an error if a non-alloced section references
+	     GOT.  */
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    {
+  non_alloc_error:
+	      _bfd_x86_elf_link_report_error (input_bfd, input_section,
+					      symtab_hdr, h, sym, howto,
+					      elf_x86_error_non_alloc);
+	      return false;
+	    }
+
 	  /* This is obsolete and treated the same as GOT64.  */
 	  base_got =3D htab->elf.sgot;
=20
@@ -3740,6 +3756,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
 	  break;
=20
 	case R_X86_64_GOTOFF64:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Relocation is relative to the start of the global offset
 	     table.  */
=20
@@ -3806,6 +3825,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
=20
 	case R_X86_64_GOTPC32:
 	case R_X86_64_GOTPC64:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Use global offset table as symbol value.  */
 	  relocation =3D htab->elf.sgotplt->output_section->vma
 		       + htab->elf.sgotplt->output_offset;
@@ -3813,6 +3835,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
 	  break;
=20
 	case R_X86_64_PLTOFF64:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Relocation is PLT entry relative to GOT.  For local
 	     symbols it's the symbol itself relative to GOT.  */
 	  if (h !=3D NULL
@@ -3849,6 +3874,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
 	  break;
=20
 	case R_X86_64_PLT32:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  /* Relocation is to the entry for this symbol in the
 	     procedure linkage table.  */
=20
@@ -4157,6 +4185,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
 	case R_X86_64_CODE_4_GOTTPOFF:
 	case R_X86_64_CODE_5_GOTTPOFF:
 	case R_X86_64_CODE_6_GOTTPOFF:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  tls_type =3D GOT_UNKNOWN;
 	  if (h =3D=3D NULL && local_got_offsets)
 	    tls_type =3D elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -4883,6 +4914,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
 	  break;
=20
 	case R_X86_64_TLSLD:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  if (! elf_x86_64_tls_transition (info, input_bfd,
 					   input_section, contents,
 					   symtab_hdr, sym_hashes,
@@ -5012,6 +5046,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *in=
fo,
 	  break;
=20
 	case R_X86_64_DTPOFF32:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  if (!bfd_link_executable (info)
 	      || (input_section->flags & SEC_CODE) =3D=3D 0)
 	    relocation -=3D _bfd_x86_elf_dtpoff_base (info);
@@ -5021,11 +5058,17 @@ elf_x86_64_relocate_section (struct bfd_link_info *=
info,
=20
 	case R_X86_64_TPOFF32:
 	case R_X86_64_TPOFF64:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  BFD_ASSERT (bfd_link_executable (info));
 	  relocation =3D elf_x86_64_tpoff (info, relocation);
 	  break;
=20
 	case R_X86_64_DTPOFF64:
+	  if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) =3D=3D 0)
+	    goto non_alloc_error;
+
 	  BFD_ASSERT ((input_section->flags & SEC_CODE) =3D=3D 0);
 	  relocation -=3D _bfd_x86_elf_dtpoff_base (info);
 	  break;
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 0f79ef58f02..e08fec52636 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -3369,23 +3369,58 @@ _bfd_x86_elf_link_report_tls_transition_error
   bfd_set_error (bfd_error_bad_value);
 }
=20
-/* Report TLS invalid section error.  */
+/* Report link error.  */
=20
 void
-_bfd_x86_elf_link_report_tls_invalid_section_error
+_bfd_x86_elf_link_report_error
   (bfd *abfd, asection *sec, Elf_Internal_Shdr *symtab_hdr,
    struct elf_link_hash_entry *h, Elf_Internal_Sym *sym,
-   reloc_howto_type *howto)
+   reloc_howto_type *howto, enum elf_x86_error_type type)
 {
   const char *name;
+  bool non_thread_local;
   if (h)
-    name =3D h->root.root.string;
+    {
+      non_thread_local =3D h->type !=3D STT_TLS;
+      name =3D h->root.root.string;
+    }
   else
-    name =3D bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
-  _bfd_error_handler
-    /* xgettext:c-format */
-    (_("%pB: relocation %s against thread local symbol `%s' in "
-       "invalid section `%pA'"), abfd, howto->name, name, sec);
+    {
+      non_thread_local =3D ELF_ST_TYPE (sym->st_info) !=3D STT_TLS;
+      name =3D bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
+      if (name[0] =3D=3D '\0')
+	name =3D "*unknown*";
+    }
+
+  switch (type)
+    {
+    case elf_x86_error_tls:
+      if (non_thread_local)
+	_bfd_error_handler
+	  /* xgettext:c-format */
+	  (_("%pB: relocation %s against non-thread local symbol "
+	     "`%s' in section `%pA'"),
+	   abfd, howto->name, name, sec);
+      else
+	_bfd_error_handler
+	  /* xgettext:c-format */
+	  (_("%pB: relocation %s against thread local symbol `%s' in "
+	     "invalid section `%pA'"), abfd, howto->name, name, sec);
+      break;
+
+    case elf_x86_error_non_alloc:
+      _bfd_error_handler
+	/* xgettext:c-format */
+	(_("%pB: relocation %s against symbol `%s' in non-alloc "
+	   "section `%pA'"),
+	 abfd, howto->name, name, sec);
+      break;
+
+    default:
+      abort ();
+      break;
+    }
+
   bfd_set_error (bfd_error_bad_value);
 }
=20
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 4932b2e43c5..430d61d3097 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -794,6 +794,12 @@ enum elf_x86_tls_error_type
   elf_x86_tls_error_yes
 };
=20
+enum elf_x86_error_type
+{
+  elf_x86_error_tls,
+  elf_x86_error_non_alloc
+};
+
 /* Set if a relocation is converted from a GOTPCREL relocation.  */
 #define R_X86_64_converted_reloc_bit (1 << 7)
=20
@@ -951,9 +957,10 @@ extern void _bfd_x86_elf_link_report_tls_transition_er=
ror
    const Elf_Internal_Rela *, const char *, const char *,
    enum elf_x86_tls_error_type) ATTRIBUTE_HIDDEN;
=20
-extern void _bfd_x86_elf_link_report_tls_invalid_section_error
+extern void _bfd_x86_elf_link_report_error
   (bfd *, asection *, Elf_Internal_Shdr *, struct elf_link_hash_entry *,
-   Elf_Internal_Sym *, reloc_howto_type *) ATTRIBUTE_HIDDEN;
+   Elf_Internal_Sym *, reloc_howto_type *,
+   enum elf_x86_error_type) ATTRIBUTE_HIDDEN;
=20
 extern bool
 _bfd_elf_x86_copy_special_section_fields