From 5474d94f03aedba2f832006dc7d680cc15792a7b Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 26 Dec 2016 00:30:45 +1030 Subject: dynrelro section for read-only dynamic symbols copied into executable Variables defined in shared libraries are copied into an executable's .bss section when code in the executable is non-PIC and thus would require dynamic text relocations to access the variable directly in the shared library. Recent x86 toolchains also copy variables into the executable to gain a small speed improvement. The problem is that if the variable was originally read-only, the copy in .bss is writable, potentially opening a security hole. This patch cures that problem by putting the copy in a section that becomes read-only after ld.so relocation, provided -z relro is in force. The patch also fixes a microblaze linker segfault on attempting to use dynamic bss variables. bfd/ PR ld/20995 * elf-bfd.h (struct elf_link_hash_table): Add sdynrelro and sreldynrelro. (struct elf_backend_data): Add want_dynrelro. * elfxx-target.h (elf_backend_want_dynrelro): Define. (elfNN_bed): Update initializer. * elflink.c (_bfd_elf_create_dynamic_sections): Create sdynrelro and sreldynrelro sections. * elf32-arm.c (elf32_arm_adjust_dynamic_symbol): Place variables copied into the executable from read-only sections into sdynrelro. (elf32_arm_size_dynamic_sections): Handle sdynrelro. (elf32_arm_finish_dynamic_symbol): Select sreldynrelro for dynamic relocs in sdynrelro. (elf_backend_want_dynrelro): Define. * elf32-hppa.c (elf32_hppa_adjust_dynamic_symbol) (elf32_hppa_size_dynamic_sections, elf32_hppa_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-i386.c (elf_i386_adjust_dynamic_symbol) (elf_i386_size_dynamic_sections, elf_i386_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-metag.c (elf_metag_adjust_dynamic_symbol) (elf_metag_size_dynamic_sections, elf_metag_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-microblaze.c (microblaze_elf_adjust_dynamic_symbol) (microblaze_elf_size_dynamic_sections) (microblaze_elf_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-nios2.c (nios2_elf32_finish_dynamic_symbol) (nios2_elf32_adjust_dynamic_symbol) (nios2_elf32_size_dynamic_sections) (elf_backend_want_dynrelro): As above. * elf32-or1k.c (or1k_elf_finish_dynamic_symbol) (or1k_elf_adjust_dynamic_symbol, or1k_elf_size_dynamic_sections) (elf_backend_want_dynrelro): As above. * elf32-ppc.c (ppc_elf_adjust_dynamic_symbol) (ppc_elf_size_dynamic_sections, ppc_elf_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-s390.c (elf_s390_adjust_dynamic_symbol) (elf_s390_size_dynamic_sections, elf_s390_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-tic6x.c (elf32_tic6x_adjust_dynamic_symbol) (elf32_tic6x_size_dynamic_sections) (elf32_tic6x_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf32-tilepro.c (tilepro_elf_adjust_dynamic_symbol) (tilepro_elf_size_dynamic_sections) (tilepro_elf_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf64-ppc.c (ppc64_elf_adjust_dynamic_symbol) (ppc64_elf_size_dynamic_sections, ppc64_elf_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf64-s390.c (elf_s390_adjust_dynamic_symbol) (elf_s390_size_dynamic_sections, elf_s390_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elf64-x86-64.c (elf_x86_64_adjust_dynamic_symbol) (elf_x86_64_size_dynamic_sections) (elf_x86_64_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elfnn-aarch64.c (elfNN_aarch64_adjust_dynamic_symbol) (elfNN_aarch64_size_dynamic_sections) (elfNN_aarch64_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elfnn-riscv.c (riscv_elf_adjust_dynamic_symbol) (riscv_elf_size_dynamic_sections, riscv_elf_finish_dynamic_symbol) (elf_backend_want_dynrelro): As above. * elfxx-mips.c (_bfd_mips_elf_adjust_dynamic_symbol) (_bfd_mips_elf_size_dynamic_sections) (_bfd_mips_vxworks_finish_dynamic_symbol): As above. * elfxx-sparc.c (_bfd_sparc_elf_adjust_dynamic_symbol) (_bfd_sparc_elf_size_dynamic_sections) (_bfd_sparc_elf_finish_dynamic_symbol): As above. * elfxx-tilegx.c (tilegx_elf_adjust_dynamic_symbol) (tilegx_elf_size_dynamic_sections) (tilegx_elf_finish_dynamic_symbol): As above. * elf32-mips.c (elf_backend_want_dynrelro): Define. * elf64-mips.c (elf_backend_want_dynrelro): Define. * elf32-sparc.c (elf_backend_want_dynrelro): Define. * elf64-sparc.c (elf_backend_want_dynrelro): Define. * elf32-tilegx.c (elf_backend_want_dynrelro): Define. * elf64-tilegx.c (elf_backend_want_dynrelro): Define. * elf32-microblaze.c (microblaze_elf_adjust_dynamic_symbol): Tidy. (microblaze_elf_size_dynamic_sections): Handle sdynbss. * elf32-nios2.c (nios2_elf32_size_dynamic_sections): Make use of linker shortcuts to dynamic sections rather than comparing names. Correctly set "got" flag. ld/ PR ld/20995 * testsuite/ld-arm/farcall-mixed-app-v5.d: Update to suit changed stub hash table traversal caused by section id increment. Accept the previous output too. * testsuite/ld-arm/farcall-mixed-app.d: Likewise. * testsuite/ld-arm/farcall-mixed-lib-v4t.d: Likewise. * testsuite/ld-arm/farcall-mixed-lib.d: Likewise. * testsuite/ld-elf/pr20995a.s, * testsuite/ld-elf/pr20995b.s, * testsuite/ld-elf/pr20995.r: New test. * testsuite/ld-elf/elf.exp: Run it. --- bfd/elf64-x86-64.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'bfd/elf64-x86-64.c') diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index d5a36bc..5b3dd8a 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -2828,7 +2828,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h) { struct elf_x86_64_link_hash_table *htab; - asection *s; + asection *s, *srel; struct elf_x86_64_link_hash_entry *eh; struct elf_dyn_relocs *p; @@ -2986,16 +2986,24 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker to copy the initial value out of the dynamic object and into the runtime process image. */ + if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + { + s = htab->elf.sdynrelro; + srel = htab->elf.sreldynrelro; + } + else + { + s = htab->elf.sdynbss; + srel = htab->elf.srelbss; + } if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) { const struct elf_backend_data *bed; bed = get_elf_backend_data (info->output_bfd); - htab->elf.srelbss->size += bed->s->sizeof_rela; + srel->size += bed->s->sizeof_rela; h->needs_copy = 1; } - s = htab->elf.sdynbss; - return _bfd_elf_adjust_dynamic_copy (info, h, s); } @@ -3811,7 +3819,8 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, || s == htab->plt_bnd || s == htab->plt_got || s == htab->plt_eh_frame - || s == htab->elf.sdynbss) + || s == htab->elf.sdynbss + || s == htab->elf.sdynrelro) { /* Strip this section if we don't need it; see the comment below. */ @@ -6024,13 +6033,15 @@ do_glob_dat: if (h->needs_copy) { Elf_Internal_Rela rela; + asection *s; /* This symbol needs a copy reloc. Set it up. */ if (h->dynindx == -1 || (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak) - || htab->elf.srelbss == NULL) + || htab->elf.srelbss == NULL + || htab->elf.sreldynrelro == NULL) abort (); rela.r_offset = (h->root.u.def.value @@ -6038,7 +6049,11 @@ do_glob_dat: + h->root.u.def.section->output_offset); rela.r_info = htab->r_info (h->dynindx, R_X86_64_COPY); rela.r_addend = 0; - elf_append_rela (output_bfd, htab->elf.srelbss, &rela); + if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + s = htab->elf.sreldynrelro; + else + s = htab->elf.srelbss; + elf_append_rela (output_bfd, s, &rela); } return TRUE; @@ -6719,6 +6734,7 @@ static const struct bfd_elf_special_section #define elf_backend_extern_protected_data 1 #define elf_backend_caches_rawsize 1 #define elf_backend_dtrel_excludes_plt 1 +#define elf_backend_want_dynrelro 1 #define elf_info_to_howto elf_x86_64_info_to_howto -- cgit v1.1