]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
x86: Check invalid GOT/PLT/TLS relocations master
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 30 Jul 2026 05:43:56 +0000 (13:43 +0800)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 4 Aug 2026 03:09:38 +0000 (11:09 +0800)
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_relocs
should issue an error for TLS relocation against non-thread local symbol.

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 against
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_error):
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.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
bfd/elf32-i386.c
bfd/elf64-x86-64.c
bfd/elfxx-x86.c
bfd/elfxx-x86.h

index ae9276cff066013f7a43e1a7a328e030ed1b0518..8ad5cb4e354bb58a22f546604a95ec699857eae8 100644 (file)
@@ -1175,8 +1175,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
        || (sec->flags & SEC_CODE) == 0))
     {
       reloc_howto_type *howto = elf_i386_rtype_to_howto (from_type);
        || (sec->flags & SEC_CODE) == 0))
     {
       reloc_howto_type *howto = 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;
     }
 
       return false;
     }
 
@@ -1749,11 +1749,15 @@ elf_i386_scan_relocs (bfd *abfd,
 
            if (tls_type >= GOT_TLS_GD
                && tls_type <= GOT_TLS_GDESC
 
            if (tls_type >= GOT_TLS_GD
                && tls_type <= GOT_TLS_GDESC
-               && (elf_section_type (sec) != SHT_PROGBITS
+               && ((h != NULL
+                    ? h->type != STT_TLS
+                    : ELF_ST_TYPE (isym->st_info) != STT_TLS)
+                   || elf_section_type (sec) != SHT_PROGBITS
                    || (sec->flags & SEC_CODE) == 0))
              {
                    || (sec->flags & SEC_CODE) == 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;
              }
 
                goto error_return;
              }
 
@@ -2585,6 +2589,18 @@ elf_i386_relocate_section (struct bfd_link_info *info,
        {
        case R_386_GOT32X:
        case R_386_GOT32:
        {
        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)) == 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 == NULL)
          /* Relocation is to the entry for this symbol in the global
             offset table.  */
          if (htab->elf.sgot == NULL)
@@ -2717,6 +2733,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_386_GOTOFF:
          break;
 
        case R_386_GOTOFF:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          /* Relocation is relative to the start of the global offset
             table.  */
 
          /* Relocation is relative to the start of the global offset
             table.  */
 
@@ -2781,6 +2800,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_386_GOTPC:
          break;
 
        case R_386_GOTPC:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          /* Use global offset table as symbol value.  */
          relocation = htab->elf.sgotplt->output_section->vma
                       + htab->elf.sgotplt->output_offset;
          /* Use global offset table as symbol value.  */
          relocation = 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;
 
        case R_386_PLT32:
          break;
 
        case R_386_PLT32:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
 
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
 
@@ -2915,6 +2940,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_386_TLS_IE:
          break;
 
        case R_386_TLS_IE:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          if (!bfd_link_executable (info))
            {
              Elf_Internal_Rela outrel;
          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:
        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)) == 0)
+           goto non_alloc_error;
+
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -3440,6 +3471,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_386_TLS_LDM:
          break;
 
        case R_386_TLS_LDM:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          if (! elf_i386_tls_transition (info, input_bfd,
                                         input_section, contents,
                                         symtab_hdr, sym_hashes,
          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;
 
        case R_386_TLS_LDO_32:
          break;
 
        case R_386_TLS_LDO_32:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          if (!bfd_link_executable (info)
              || (input_section->flags & SEC_CODE) == 0)
            relocation -= _bfd_x86_elf_dtpoff_base (info);
          if (!bfd_link_executable (info)
              || (input_section->flags & SEC_CODE) == 0)
            relocation -= _bfd_x86_elf_dtpoff_base (info);
@@ -3522,6 +3559,9 @@ elf_i386_relocate_section (struct bfd_link_info *info,
 
        case R_386_TLS_LE_32:
        case R_386_TLS_LE:
 
        case R_386_TLS_LE_32:
        case R_386_TLS_LE:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          if (!bfd_link_executable (info))
            {
              Elf_Internal_Rela outrel;
          if (!bfd_link_executable (info))
            {
              Elf_Internal_Rela outrel;
index 3700520b40f80ed97b6f2a5bc997c88d4cdd3ec3..878feb20b85f08769782e5bc261f226fbee67696 100644 (file)
@@ -1633,8 +1633,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
     {
       reloc_howto_type *howto = elf_x86_64_rtype_to_howto (abfd,
                                                           from_type);
     {
       reloc_howto_type *howto = 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;
     }
 
       return false;
     }
 
@@ -2772,11 +2772,15 @@ need_got:
 
            if (tls_type >= GOT_TLS_GD
                && tls_type <= GOT_TLS_GDESC
 
            if (tls_type >= GOT_TLS_GD
                && tls_type <= GOT_TLS_GDESC
-               && (elf_section_type (sec) != SHT_PROGBITS
+               && ((h != NULL
+                    ? h->type != STT_TLS
+                    : ELF_ST_TYPE (isym->st_info) != STT_TLS)
+                   || elf_section_type (sec) != SHT_PROGBITS
                    || (sec->flags & SEC_CODE) == 0))
              {
                    || (sec->flags & SEC_CODE) == 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;
              }
 
                goto error_return;
              }
 
@@ -3602,6 +3606,18 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
        case R_X86_64_GOTPCREL64:
          /* Use global offset table entry as symbol value.  */
        case R_X86_64_GOTPLT64:
        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)) == 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 = htab->elf.sgot;
 
          /* This is obsolete and treated the same as GOT64.  */
          base_got = htab->elf.sgot;
 
@@ -3740,6 +3756,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_X86_64_GOTOFF64:
          break;
 
        case R_X86_64_GOTOFF64:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          /* Relocation is relative to the start of the global offset
             table.  */
 
          /* Relocation is relative to the start of the global offset
             table.  */
 
@@ -3806,6 +3825,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
 
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC64:
 
        case R_X86_64_GOTPC32:
        case R_X86_64_GOTPC64:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          /* Use global offset table as symbol value.  */
          relocation = htab->elf.sgotplt->output_section->vma
                       + htab->elf.sgotplt->output_offset;
          /* Use global offset table as symbol value.  */
          relocation = htab->elf.sgotplt->output_section->vma
                       + htab->elf.sgotplt->output_offset;
@@ -3813,6 +3835,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_X86_64_PLTOFF64:
          break;
 
        case R_X86_64_PLTOFF64:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 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 != NULL
          /* Relocation is PLT entry relative to GOT.  For local
             symbols it's the symbol itself relative to GOT.  */
          if (h != NULL
@@ -3849,6 +3874,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_X86_64_PLT32:
          break;
 
        case R_X86_64_PLT32:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
 
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
 
@@ -4157,6 +4185,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
        case R_X86_64_CODE_4_GOTTPOFF:
        case R_X86_64_CODE_5_GOTTPOFF:
        case R_X86_64_CODE_6_GOTTPOFF:
        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)) == 0)
+           goto non_alloc_error;
+
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
          tls_type = GOT_UNKNOWN;
          if (h == NULL && local_got_offsets)
            tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx];
@@ -4883,6 +4914,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
          break;
 
        case R_X86_64_TLSLD:
          break;
 
        case R_X86_64_TLSLD:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          if (! elf_x86_64_tls_transition (info, input_bfd,
                                           input_section, contents,
                                           symtab_hdr, sym_hashes,
          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 *info,
          break;
 
        case R_X86_64_DTPOFF32:
          break;
 
        case R_X86_64_DTPOFF32:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          if (!bfd_link_executable (info)
              || (input_section->flags & SEC_CODE) == 0)
            relocation -= _bfd_x86_elf_dtpoff_base (info);
          if (!bfd_link_executable (info)
              || (input_section->flags & SEC_CODE) == 0)
            relocation -= _bfd_x86_elf_dtpoff_base (info);
@@ -5021,11 +5058,17 @@ elf_x86_64_relocate_section (struct bfd_link_info *info,
 
        case R_X86_64_TPOFF32:
        case R_X86_64_TPOFF64:
 
        case R_X86_64_TPOFF32:
        case R_X86_64_TPOFF64:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          BFD_ASSERT (bfd_link_executable (info));
          relocation = elf_x86_64_tpoff (info, relocation);
          break;
 
        case R_X86_64_DTPOFF64:
          BFD_ASSERT (bfd_link_executable (info));
          relocation = elf_x86_64_tpoff (info, relocation);
          break;
 
        case R_X86_64_DTPOFF64:
+         if ((input_section->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0)
+           goto non_alloc_error;
+
          BFD_ASSERT ((input_section->flags & SEC_CODE) == 0);
          relocation -= _bfd_x86_elf_dtpoff_base (info);
          break;
          BFD_ASSERT ((input_section->flags & SEC_CODE) == 0);
          relocation -= _bfd_x86_elf_dtpoff_base (info);
          break;
index 0f79ef58f025335cda9161741e7a3236eef94193..e08fec52636ccb144b3d95014068053dae08a6c6 100644 (file)
@@ -3369,23 +3369,58 @@ _bfd_x86_elf_link_report_tls_transition_error
   bfd_set_error (bfd_error_bad_value);
 }
 
   bfd_set_error (bfd_error_bad_value);
 }
 
-/* Report TLS invalid section error.  */
+/* Report link error.  */
 
 void
 
 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,
   (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;
 {
   const char *name;
+  bool non_thread_local;
   if (h)
   if (h)
-    name = h->root.root.string;
+    {
+      non_thread_local = h->type != STT_TLS;
+      name = h->root.root.string;
+    }
   else
   else
-    name = 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 = ELF_ST_TYPE (sym->st_info) != STT_TLS;
+      name = bfd_elf_sym_name (abfd, symtab_hdr, sym, NULL);
+      if (name[0] == '\0')
+       name = "*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);
 }
 
   bfd_set_error (bfd_error_bad_value);
 }
 
index 4932b2e43c5272df17939e4a77c8a9d5a0b231ec..430d61d30970e116ace4a66866a09be290d04ad7 100644 (file)
@@ -794,6 +794,12 @@ enum elf_x86_tls_error_type
   elf_x86_tls_error_yes
 };
 
   elf_x86_tls_error_yes
 };
 
+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)
 
 /* Set if a relocation is converted from a GOTPCREL relocation.  */
 #define R_X86_64_converted_reloc_bit (1 << 7)
 
@@ -951,9 +957,10 @@ extern void _bfd_x86_elf_link_report_tls_transition_error
    const Elf_Internal_Rela *, const char *, const char *,
    enum elf_x86_tls_error_type) ATTRIBUTE_HIDDEN;
 
    const Elf_Internal_Rela *, const char *, const char *,
    enum elf_x86_tls_error_type) ATTRIBUTE_HIDDEN;
 
-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 *,
   (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;
 
 extern bool
 _bfd_elf_x86_copy_special_section_fields
 
 extern bool
 _bfd_elf_x86_copy_special_section_fields