From 471130b39c03623ec6d78ece377ff4da3f6bfe7b Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 30 Jul 2026 13:43:56 +0800 Subject: [PATCH] x86: Check invalid GOT/PLT/TLS relocations 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 --- 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) == 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; } @@ -1749,11 +1749,15 @@ elf_i386_scan_relocs (bfd *abfd, 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)) { - _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; } @@ -2585,6 +2589,18 @@ elf_i386_relocate_section (struct bfd_link_info *info, { 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) @@ -2717,6 +2733,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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. */ @@ -2781,6 +2800,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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; @@ -2788,6 +2810,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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. */ @@ -2915,6 +2940,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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; @@ -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)) == 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]; @@ -3440,6 +3471,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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, @@ -3512,6 +3546,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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); @@ -3522,6 +3559,9 @@ elf_i386_relocate_section (struct bfd_link_info *info, 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; 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 = 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; } @@ -2772,11 +2772,15 @@ need_got: 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)) { - _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; } @@ -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: + /* 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; @@ -3740,6 +3756,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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. */ @@ -3806,6 +3825,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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; @@ -3813,6 +3835,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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 @@ -3849,6 +3874,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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. */ @@ -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: + 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]; @@ -4883,6 +4914,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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, @@ -5012,6 +5046,9 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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); @@ -5021,11 +5058,17 @@ elf_x86_64_relocate_section (struct bfd_link_info *info, 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: + 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; 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); } -/* Report TLS invalid section error. */ +/* Report link error. */ 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 = h->root.root.string; + { + non_thread_local = h->type != STT_TLS; + name = h->root.root.string; + } 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); } 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 }; +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) @@ -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; -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; extern bool _bfd_elf_x86_copy_special_section_fields -- 2.47.3