[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