From patchwork Tue Dec 19 13:45:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Lu, Hongjiu" X-Patchwork-Id: 25008 Received: (qmail 61125 invoked by alias); 19 Dec 2017 13:45:36 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 60963 invoked by uid 89); 19 Dec 2017 13:45:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, NO_DNS_FOR_FROM, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy= X-HELO: mga07.intel.com X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False X-ExtLoop1: 1 Date: Tue, 19 Dec 2017 05:45:00 -0800 From: "H.J. Lu" To: GNU C Library Cc: Igor Tsimbalist , Andrew Senkevich Subject: [PATCH] x86: Support IBT and SHSTK in Intel CET [BZ #21598] Message-ID: <20171219134500.GA1143@gmail.com> Reply-To: "H.J. Lu" MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.1 (2017-09-22) Intel Control-flow Enforcement Technology (CET) instructions: https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-en forcement-technology-preview.pdf includes Indirect Branch Tracking (IBT) and Shadow Stack (SHSTK). GNU_PROPERTY_X86_FEATURE_1_IBT is added to GNU program property to indicate that all executable sections are compatible with IBT when ENDBR instruction starts each valid target where an indirect branch instruction can land. Linker sets GNU_PROPERTY_X86_FEATURE_1_IBT on output only if it is set on all relocatable inputs. On an IBT capable processor, the following steps should be taken: 1. When loading an executable without an interpreter, enable IBT and lock IBT if GNU_PROPERTY_X86_FEATURE_1_IBT is set on the executable. 2. When loading an executable with an interpreter, enable IBT if GNU_PROPERTY_X86_FEATURE_1_IBT is set on the interpreter. a. If GNU_PROPERTY_X86_FEATURE_1_IBT isn't set on the executable, disable IBT. b. Lock IBT. 3. If IBT is enabled, when loading a shared object without GNU_PROPERTY_X86_FEATURE_1_IBT: a. If legacy interwork is allowed, then mark all pages in executable PT_LOAD segments in legacy code page bitmap. Failure of legacy code page bitmap allocation causes an error. b. If legacy interwork isn't allowed, it causes an error. GNU_PROPERTY_X86_FEATURE_1_SHSTK is added to GNU program property to indicate that all executable sections are compatible with SHSTK where return address popped from shadow stack always matches return address popped from normal stack. Linker sets GNU_PROPERTY_X86_FEATURE_1_SHSTK on output only if it is set on all relocatable inputs. On a SHSTK capable processor, the following steps should be taken: 1. When loading an executable without an interpreter, enable SHSTK if GNU_PROPERTY_X86_FEATURE_1_SHSTK is set on the executable. 2. When loading an executable with an interpreter, enable SHSTK if GNU_PROPERTY_X86_FEATURE_1_SHSTK is set on interpreter. a. If GNU_PROPERTY_X86_FEATURE_1_SHSTK isn't set on the executable or any shared objects loaded via the DT_NEEDED tag, disable SHSTK. b. Otherwise lock SHSTK. 3. After SHSTK is enabled, it is an error to load a shared object without GNU_PROPERTY_X86_FEATURE_1_SHSTK. When glibc is built with a CET-enabled compiler, CET is enabled by default, unless --disable-cet is used to configure glibc. When CET is enabled, both compiler and assembler must support CET. Otherwise, it is a configure-time error. To support CET run-time control, 1. _dl_x86_feature_1 is added to the writable ld.so namespace to indicate if IBT or SHSTK are enabled at run-time. It should be initialized by init_cpu_features. 2. For dynamic executables: a. A l_cet field is added to struct link_map to indicate if IBT or SHSTK is enabled in an ELF module. The optional DL_PROCESS_PT_NOTE is called to process PT_NOTE segment for GNU program property and set l_cet. b. _dl_start_user calls _dl_cet_init, instead of _dl_init, which sets up IBT and SHSTK. c. DL_OPEN_CHECK is added to check IBT and SHSTK compatibilty when dlopening a shared object. 3. Replace i386 _dl_runtime_resolve and _dl_runtime_profile with _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, respectively if SHSTK is enabled. from CET-enabled GCC is automatically included by assembly codes to add GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK to GNU program property. _CET_ENDBR is added at the entrance of all assembly functions whose address may be taken. -fcf-protection -mshstk is incompatible with makecontext family functions since they can't properly set up and destroy shadow stack pointer. When It is an error when -fcf-protection -mshstk is used with . When is used, GNU_PROPERTY_X86_FEATURE_1_SHSTK shouldn't be set on the program. We will submit a separate patch for kernel interface when kernel API is settled. Any comments? H.J. [BZ #21598] * config.h.in (ENABLE_CET): New #undef. * configure.ac: Add --enable-cet. * configure: Regenerated. * elf/dl-load.c (filebuf): Moved before "dynamic-link.h". (_dl_map_object_from_fd): Call DL_PROCESS_PT_NOTE on PT_NOTE segment if DL_PROCESS_PT_NOTE is defined. * elf/rtld.c (dl_main): Likewise. * elf/dl-open.c (dl_open_worker): Call DL_OPEN_CHECK if it is defined. * sysdeps/unix/sysv/linux/i386/dl-cet.c: New file. * sysdeps/unix/sysv/linux/i386/dl-machine.h: Likewise. * sysdeps/unix/sysv/linux/x86/check-cet.awk: Likewise. * sysdeps/unix/sysv/linux/x86/configure: Likewise. * sysdeps/unix/sysv/linux/x86/configure.ac: Likewise. * sysdeps/unix/sysv/linux/x86/dl-cet.c: Likewise. * sysdeps/unix/sysv/linux/x86/dl-cet.h: Likewise. * sysdeps/unix/sysv/linux/x86/dl-procruntime.c: Likewise. * sysdeps/unix/sysv/linux/x86/ldsodefs.h: Likewise. * sysdeps/unix/sysv/linux/x86/link_map.h: Likewise. * sysdeps/unix/sysv/linux/x86/stdlib/ucontext.h: Likewise. * sysdeps/unix/sysv/linux/x86/tst-setcontext3-shstk.sh: Likewise. * sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c: Likewise. * sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh: Likewise. * sysdeps/unix/sysv/linux/x86/ucontext.h: Likewise. * sysdeps/unix/sysv/linux/x86_64/dl-machine.h: Likewise. * sysdeps/i386/dl-machine.h (DL_INIT): New. (_dl_start_user): Replace _dl_init with DL_INIT. * sysdeps/i386/dl-trampoline.S (_dl_runtime_resolve): Add _CET_ENDBR. (_dl_runtime_profile): Likewise. (_dl_runtime_resolve_shstk): New. (_dl_runtime_profile_shstk): Likewise. * sysdeps/unix/sysv/linux/x86/Makefile (tests-special): Add $(objpfx)tst-setcontext3-shstk.out. ($(objpfx)tst-setcontext3-shstk.out): New target. (sysdep-dl-routines): Add dl-cet if CET is enabled. (tests-special): Add $(objpfx)tst-ucontext-1.out if CET is enabled. ($(objpfx)tst-ucontext-1.out): New target if CET is enabled. (CFLAGS-.o): Add -fcf-protection -mcet if CET is enabled. (CFLAGS-.os): Likewise. (CFLAGS-.op): Likewise. (CFLAGS-.oS): Likewise. (asm-CPPFLAGS): Add -fcf-protection -mcet -include cet.h if CET is enabled. (CFLAGS-tst-context1.c): Add -fcf-protection=branch -mno-shstk -mibt. (CFLAGS-bug-getcontext.c): Likewise. (CFLAGS-tst-makecontext.c): Likewise. (CFLAGS-tst-makecontext2.c): Likewise. (CFLAGS-tst-makecontext3.c): Likewise. (CFLAGS-tst-setcontext.c): Likewise. (CFLAGS-tst-setcontext2.c): Likewise. (CFLAGS-tst-setcontext3.c): Likewise. (CFLAGS-tst-xbzero-opt.c): Likewise. (tests-special): Add $(objpfx)check-cet.out. (cet-built-dso): New. (+$(cet-built-dso:=.note)): Likewise. (common-generated): Add $(cet-built-dso:$(common-objpfx)%=%.note). ($(objpfx)check-cet.out): New. (generated): Add check-cet.out. * sysdeps/x86/sysdep.h (_CET_ENDBR): Define if not defined. (ENTRY): Add _CET_ENDBR. * sysdeps/x86_64/dl-machine.h (DL_INIT): New. (_dl_start_user): Replace _dl_init with DL_INIT. * sysdeps/x86_64/x32/dl-machine.h (_dl_start_user): Likewise. * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Add _CET_ENDBR. (_dl_runtime_profile): Likewise. --- config.h.in | 4 + configure | 11 ++ configure.ac | 6 + elf/dl-load.c | 61 +++++----- elf/dl-open.c | 4 + elf/rtld.c | 8 ++ sysdeps/i386/dl-machine.h | 6 +- sysdeps/i386/dl-trampoline.S | 72 ++++++++++++ sysdeps/unix/sysv/linux/i386/dl-cet.c | 66 +++++++++++ sysdeps/unix/sysv/linux/i386/dl-machine.h | 23 ++++ sysdeps/unix/sysv/linux/x86/Makefile | 81 +++++++++++++ sysdeps/unix/sysv/linux/x86/check-cet.awk | 35 ++++++ sysdeps/unix/sysv/linux/x86/configure | 72 ++++++++++++ sysdeps/unix/sysv/linux/x86/configure.ac | 48 ++++++++ sysdeps/unix/sysv/linux/x86/dl-cet.c | 88 +++++++++++++++ sysdeps/unix/sysv/linux/x86/dl-cet.h | 125 +++++++++++++++++++++ sysdeps/unix/sysv/linux/x86/dl-procruntime.c | 57 ++++++++++ sysdeps/unix/sysv/linux/x86/ldsodefs.h | 60 ++++++++++ sysdeps/unix/sysv/linux/x86/link_map.h | 26 +++++ sysdeps/unix/sysv/linux/x86/stdlib/ucontext.h | 1 + .../unix/sysv/linux/x86/tst-setcontext3-shstk.sh | 34 ++++++ sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c | 20 ++++ sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh | 37 ++++++ sysdeps/unix/sysv/linux/x86/ucontext.h | 56 +++++++++ sysdeps/unix/sysv/linux/x86_64/dl-machine.h | 27 +++++ sysdeps/x86/cpu-features.h | 5 + sysdeps/x86/sysdep.h | 5 + sysdeps/x86_64/dl-machine.h | 6 +- sysdeps/x86_64/dl-trampoline.h | 2 + sysdeps/x86_64/x32/dl-machine.h | 2 +- 30 files changed, 1020 insertions(+), 28 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/i386/dl-cet.c create mode 100644 sysdeps/unix/sysv/linux/i386/dl-machine.h create mode 100644 sysdeps/unix/sysv/linux/x86/check-cet.awk create mode 100644 sysdeps/unix/sysv/linux/x86/configure create mode 100644 sysdeps/unix/sysv/linux/x86/configure.ac create mode 100644 sysdeps/unix/sysv/linux/x86/dl-cet.c create mode 100644 sysdeps/unix/sysv/linux/x86/dl-cet.h create mode 100644 sysdeps/unix/sysv/linux/x86/dl-procruntime.c create mode 100644 sysdeps/unix/sysv/linux/x86/ldsodefs.h create mode 100644 sysdeps/unix/sysv/linux/x86/link_map.h create mode 100644 sysdeps/unix/sysv/linux/x86/stdlib/ucontext.h create mode 100755 sysdeps/unix/sysv/linux/x86/tst-setcontext3-shstk.sh create mode 100644 sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c create mode 100755 sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh create mode 100644 sysdeps/unix/sysv/linux/x86/ucontext.h create mode 100644 sysdeps/unix/sysv/linux/x86_64/dl-machine.h diff --git a/config.h.in b/config.h.in index d928e7dd86..06f3958cad 100644 --- a/config.h.in +++ b/config.h.in @@ -131,6 +131,10 @@ /* Define if __stack_chk_guard canary should be randomized at program startup. */ #undef ENABLE_STACKGUARD_RANDOMIZE +/* Define if Intel Control-flow Enforcement Technology (CET) should be + enabled. */ +#undef ENABLE_CET + /* Package description. */ #undef PKGVERSION diff --git a/configure b/configure index 7a8bd3f817..fb7b41b9ed 100755 --- a/configure +++ b/configure @@ -788,6 +788,7 @@ enable_nscd enable_pt_chown enable_tunables enable_mathvec +enable_cet with_cpu ' ac_precious_vars='build_alias @@ -1461,6 +1462,8 @@ Optional Features: 'no' and 'valstring' --enable-mathvec Enable building and installing mathvec [default depends on architecture] + --enable-cet enable Intel Control-flow Enforcement Technology + (CET), x86 only Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -3741,6 +3744,14 @@ else fi +# Check whether --enable-cet was given. +if test "${enable_cet+set}" = set; then : + enableval=$enable_cet; enable_cet=$enableval +else + enable_cet=default +fi + + # We keep the original values in `$config_*' and never modify them, so we # can write them unchanged into config.make. Everything else uses # $machine, $vendor, and $os, and changes them whenever convenient. diff --git a/configure.ac b/configure.ac index ca1282a6b3..2568db5533 100644 --- a/configure.ac +++ b/configure.ac @@ -453,6 +453,12 @@ AC_ARG_ENABLE([mathvec], [build_mathvec=$enableval], [build_mathvec=notset]) +AC_ARG_ENABLE([cet], + AC_HELP_STRING([--enable-cet], + [enable Intel Control-flow Enforcement Technology (CET), x86 only]), + [enable_cet=$enableval], + [enable_cet=default]) + # We keep the original values in `$config_*' and never modify them, so we # can write them unchanged into config.make. Everything else uses # $machine, $vendor, and $os, and changes them whenever convenient. diff --git a/elf/dl-load.c b/elf/dl-load.c index e7d97dcc56..fd8c83959c 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -30,6 +30,32 @@ #include #include #include + +/* Type for the buffer we put the ELF header and hopefully the program + header. This buffer does not really have to be too large. In most + cases the program header follows the ELF header directly. If this + is not the case all bets are off and we can make the header + arbitrarily large and still won't get it read. This means the only + question is how large are the ELF and program header combined. The + ELF header 32-bit files is 52 bytes long and in 64-bit files is 64 + bytes long. Each program header entry is again 32 and 56 bytes + long respectively. I.e., even with a file which has 10 program + header entries we only have to read 372B/624B respectively. Add to + this a bit of margin for program notes and reading 512B and 832B + for 32-bit and 64-bit files respecitvely is enough. If this + heuristic should really fail for some file the code in + `_dl_map_object_from_fd' knows how to recover. */ +struct filebuf +{ + ssize_t len; +#if __WORDSIZE == 32 +# define FILEBUF_SIZE 512 +#else +# define FILEBUF_SIZE 832 +#endif + char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); +}; + #include "dynamic-link.h" #include #include @@ -70,31 +96,6 @@ int __stack_prot attribute_hidden attribute_relro #endif -/* Type for the buffer we put the ELF header and hopefully the program - header. This buffer does not really have to be too large. In most - cases the program header follows the ELF header directly. If this - is not the case all bets are off and we can make the header - arbitrarily large and still won't get it read. This means the only - question is how large are the ELF and program header combined. The - ELF header 32-bit files is 52 bytes long and in 64-bit files is 64 - bytes long. Each program header entry is again 32 and 56 bytes - long respectively. I.e., even with a file which has 10 program - header entries we only have to read 372B/624B respectively. Add to - this a bit of margin for program notes and reading 512B and 832B - for 32-bit and 64-bit files respecitvely is enough. If this - heuristic should really fail for some file the code in - `_dl_map_object_from_fd' knows how to recover. */ -struct filebuf -{ - ssize_t len; -#if __WORDSIZE == 32 -# define FILEBUF_SIZE 512 -#else -# define FILEBUF_SIZE 832 -#endif - char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); -}; - /* This is the decomposed LD_LIBRARY_PATH search path. */ static struct r_search_path_struct env_path_list attribute_relro; @@ -1133,6 +1134,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, l->l_relro_addr = ph->p_vaddr; l->l_relro_size = ph->p_memsz; break; + +#ifdef DL_PROCESS_PT_NOTE + case PT_NOTE: + if (DL_PROCESS_PT_NOTE (l, ph, fd, fbp)) + { + errstring = N_("cannot process note segment"); + goto call_lose; + } + break; +#endif } if (__glibc_unlikely (nloadcmds == 0)) diff --git a/elf/dl-open.c b/elf/dl-open.c index 68907bf532..0db07418e7 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -299,6 +299,10 @@ dl_open_worker (void *a) _dl_debug_state (); LIBC_PROBE (map_complete, 3, args->nsid, r, new); +#ifdef DL_OPEN_CHECK + DL_OPEN_CHECK (new); +#endif + /* Print scope information. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) _dl_show_scope (new, 0); diff --git a/elf/rtld.c b/elf/rtld.c index c01b7e3641..11ebe17991 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -1241,6 +1241,14 @@ of this helper program; chances are you did not intend to run this program.\n\ main_map->l_relro_addr = ph->p_vaddr; main_map->l_relro_size = ph->p_memsz; break; + +#ifdef DL_PROCESS_PT_NOTE + case PT_NOTE: + if (DL_PROCESS_PT_NOTE (main_map, ph)) + _dl_error_printf ("\ +ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + break; +#endif } /* Adjust the address of the TLS initialization image in case diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h index 2e17eba5c0..77a2049134 100644 --- a/sysdeps/i386/dl-machine.h +++ b/sysdeps/i386/dl-machine.h @@ -137,6 +137,10 @@ extern ElfW(Addr) _dl_profile_fixup (struct link_map *l, where the dynamic linker should not map anything. */ #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL +#ifndef DL_INIT +# define DL_INIT "_dl_init" +#endif + /* Initial entry point code for the dynamic linker. The C function `_dl_start' is the real entry point; its return value is the user program's entry point. */ @@ -194,7 +198,7 @@ _dl_start_user:\n\ # Clear %ebp, so that even constructors have terminated backchain.\n\ xorl %ebp, %ebp\n\ # Call the function to run the initializers.\n\ - call _dl_init\n\ + call " DL_INIT "\n\ # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\ leal _dl_fini@GOTOFF(%ebx), %edx\n\ # Restore %esp _start expects.\n\ diff --git a/sysdeps/i386/dl-trampoline.S b/sysdeps/i386/dl-trampoline.S index 6e7f3aef92..cd3c1a5f7c 100644 --- a/sysdeps/i386/dl-trampoline.S +++ b/sysdeps/i386/dl-trampoline.S @@ -32,6 +32,7 @@ .align 16 _dl_runtime_resolve: cfi_adjust_cfa_offset (8) + _CET_ENDBR pushl %eax # Preserve registers otherwise clobbered. cfi_adjust_cfa_offset (4) pushl %ecx @@ -50,14 +51,85 @@ _dl_runtime_resolve: cfi_endproc .size _dl_runtime_resolve, .-_dl_runtime_resolve +# The SHSTK compatible version. + .text + .globl _dl_runtime_resolve_shstk + .type _dl_runtime_resolve_shstk, @function + cfi_startproc + .align 16 +_dl_runtime_resolve_shstk: + cfi_adjust_cfa_offset (8) + _CET_ENDBR + pushl %eax # Preserve registers otherwise clobbered. + cfi_adjust_cfa_offset (4) + pushl %edx + cfi_adjust_cfa_offset (4) + movl 12(%esp), %edx # Copy args pushed by PLT in register. Note + movl 8(%esp), %eax # that `fixup' takes its parameters in regs. + call _dl_fixup # Call resolver. + movl (%esp), %edx # Get register content back. + movl %eax, %ecx # Store the function address. + movl 4(%esp), %eax # Get register content back. + addl $16, %esp # Adjust stack: PLT1 + PLT2 + %eax + %edx + cfi_adjust_cfa_offset (-16) + jmp *%ecx # Jump to function address. + cfi_endproc + .size _dl_runtime_resolve_shstk, .-_dl_runtime_resolve_shstk #ifndef PROF +# The SHSTK compatible version. + .globl _dl_runtime_profile_shstk + .type _dl_runtime_profile_shstk, @function + cfi_startproc + .align 16 +_dl_runtime_profile_shstk: + cfi_adjust_cfa_offset (8) + _CET_ENDBR + pushl %esp + cfi_adjust_cfa_offset (4) + addl $8, (%esp) # Account for the pushed PLT data + pushl %ebp + cfi_adjust_cfa_offset (4) + pushl %eax # Preserve registers otherwise clobbered. + cfi_adjust_cfa_offset (4) + pushl %ecx + cfi_adjust_cfa_offset (4) + pushl %edx + cfi_adjust_cfa_offset (4) + movl %esp, %ecx + subl $8, %esp + cfi_adjust_cfa_offset (8) + movl $-1, 4(%esp) + leal 4(%esp), %edx + movl %edx, (%esp) + pushl %ecx # Address of the register structure + cfi_adjust_cfa_offset (4) + movl 40(%esp), %ecx # Load return address + movl 36(%esp), %edx # Copy args pushed by PLT in register. Note + movl 32(%esp), %eax # that `fixup' takes its parameters in regs. + call _dl_profile_fixup # Call resolver. + cfi_adjust_cfa_offset (-8) + movl (%esp), %edx + testl %edx, %edx + jns 1f + movl 4(%esp), %edx # Get register content back. + movl %eax, %ecx # Store the function address. + movl 12(%esp), %eax # Get register content back. + # Adjust stack: PLT1 + PLT2 + %esp + %ebp + %eax + %ecx + %edx + # + free. + addl $32, %esp + cfi_adjust_cfa_offset (-32) + jmp *%ecx # Jump to function address. + cfi_endproc + .size _dl_runtime_profile_shstk, .-_dl_runtime_profile_shstk + .globl _dl_runtime_profile .type _dl_runtime_profile, @function cfi_startproc .align 16 _dl_runtime_profile: cfi_adjust_cfa_offset (8) + _CET_ENDBR pushl %esp cfi_adjust_cfa_offset (4) addl $8, (%esp) # Account for the pushed PLT data diff --git a/sysdeps/unix/sysv/linux/i386/dl-cet.c b/sysdeps/unix/sysv/linux/i386/dl-cet.c new file mode 100644 index 0000000000..11d9010fdc --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/dl-cet.c @@ -0,0 +1,66 @@ +/* Linux/i386 CET initializers function. + Copyright (C) 2017 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef SHARED +# define LINKAGE static inline +# define _dl_cet_init cet_init +# include +# undef _dl_cet_init + +void +_dl_cet_init (struct link_map *main_map, int argc, char **argv, char **env) +{ + cet_init (main_map, argc, argv, env); + + if ((GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) + { + /* Replace _dl_runtime_resolve and _dl_runtime_profile with + _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, + respectively if SHSTK is enabled. */ + extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; + extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; + extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; + extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; + unsigned int i; + struct link_map *l; + Elf32_Addr *got; + + if (main_map->l_info[DT_JMPREL]) + { + got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]); + if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) + got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; + else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) + got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; + } + + i = main_map->l_searchlist.r_nlist; + while (i-- > 0) + { + l = main_map->l_initfini[i]; + if (l->l_info[DT_JMPREL]) + { + got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]); + if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) + got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; + else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) + got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; + } + } + } +} +#endif diff --git a/sysdeps/unix/sysv/linux/i386/dl-machine.h b/sysdeps/unix/sysv/linux/i386/dl-machine.h new file mode 100644 index 0000000000..303358ffab --- /dev/null +++ b/sysdeps/unix/sysv/linux/i386/dl-machine.h @@ -0,0 +1,23 @@ +/* Machine-dependent ELF dynamic relocation inline functions. + Linux/i386 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef ENABLE_CET +# include +#endif +#include diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile index c55a43e58d..bf16c986ff 100644 --- a/sysdeps/unix/sysv/linux/x86/Makefile +++ b/sysdeps/unix/sysv/linux/x86/Makefile @@ -24,3 +24,84 @@ ifeq ($(subdir),setjmp) gen-as-const-headers += jmp_buf-ssp.sym tests += tst-saved_mask-1 endif + +ifeq ($(subdir),stdlib) +# Check that GNU_PROPERTY_X86_FEATURE_1_SHSTK isn't set. +tests-special += $(objpfx)tst-setcontext3-shstk.out +endif + +$(objpfx)tst-setcontext3-shstk.out: $(..)sysdeps/unix/sysv/linux/x86/tst-setcontext3-shstk.sh $(objpfx)tst-setcontext3 + $(SHELL) $< $(common-objpfx)stdlib/ $(READELF) > $@; \ + $(evaluate-test) + +ifeq ($(enable-cet),yes) +ifeq ($(subdir),elf) +sysdep-dl-routines += dl-cet +endif + +ifeq ($(subdir),stdlib) +# Check for error with -fcf-protection -mshstk on makecontext family +# functions. +tests-special += $(objpfx)tst-ucontext-1.out +endif + +$(objpfx)tst-ucontext-1.out: $(..)sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh \ + $(..)sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c + $(SHELL) $< "$(CC)" "-D_ISOMAC $(+includes)" \ + $(filter-out $<,$^) > $@; \ + $(evaluate-test) + +# Add -fcf-protection -mcet to CFLAGS when CET is enabled. +CFLAGS-.o += -fcf-protection -mcet +CFLAGS-.os += -fcf-protection -mcet +CFLAGS-.op += -fcf-protection -mcet +CFLAGS-.oS += -fcf-protection -mcet + +# Compile assembly codes with when CET is enabled. +asm-CPPFLAGS += -fcf-protection -mcet -include cet.h + +ifeq ($(subdir),nptl) +CFLAGS-tst-context1.c += -fcf-protection=branch -mno-shstk -mibt +endif + +ifeq ($(subdir),stdlib) +CFLAGS-bug-getcontext.c += -fcf-protection=branch -mno-shstk -mibt +CFLAGS-tst-makecontext.c += -fcf-protection=branch -mno-shstk -mibt +CFLAGS-tst-makecontext2.c += -fcf-protection=branch -mno-shstk -mibt +CFLAGS-tst-makecontext3.c += -fcf-protection=branch -mno-shstk -mibt +CFLAGS-tst-setcontext.c += -fcf-protection=branch -mno-shstk -mibt +CFLAGS-tst-setcontext2.c += -fcf-protection=branch -mno-shstk -mibt +CFLAGS-tst-setcontext3.c += -fcf-protection=branch -mno-shstk -mibt +endif + +ifeq ($(subdir),string) +CFLAGS-tst-xbzero-opt.c += -fcf-protection=branch -mno-shstk -mibt +endif + +ifeq ($(subdir),elf) +ifeq (yes,$(build-shared)) +tests-special += $(objpfx)check-cet.out +endif + +# FIXME: Can't use all-built-dso in elf/Makefile since this file is +# processed before elf/Makefile. Duplicate it here. +cet-built-dso := $(common-objpfx)elf/ld.so $(common-objpfx)libc.so \ + $(filter-out $(common-objpfx)linkobj/libc.so, \ + $(sort $(wildcard $(addprefix $(common-objpfx), \ + */lib*.so \ + iconvdata/*.so)))) + +$(cet-built-dso:=.note): %.note: % + @rm -f $@T + LC_ALL=C $(READELF) -n $< > $@T + test -s $@T + mv -f $@T $@ +common-generated += $(cet-built-dso:$(common-objpfx)%=%.note) + +$(objpfx)check-cet.out: $(..)sysdeps/unix/sysv/linux/x86/check-cet.awk \ + $(cet-built-dso:=.note) + LC_ALL=C $(AWK) -f $^ > $@; \ + $(evaluate-test) +generated += check-cet.out +endif +endif diff --git a/sysdeps/unix/sysv/linux/x86/check-cet.awk b/sysdeps/unix/sysv/linux/x86/check-cet.awk new file mode 100644 index 0000000000..e3723f4839 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/check-cet.awk @@ -0,0 +1,35 @@ +# This awk script expects to get command-line files that are each +# the output of 'readelf -n' on a single shared object. +# It exits successfully (0) if all of them contained the CET property. +# It fails (1) if any didn't contain the CET property +# It fails (2) if the input did not take the expected form. + +BEGIN { result = cet = sanity = 0 } + +function check_one(name) { + if (!sanity) { + print name ": *** input did not look like readelf -n output"; + result = 2; + } else if (cet) { + print name ": OK"; + } else { + print name ": *** no CET property found"; + result = result ? result : 1; + } + + cet = sanity = 0; +} + +FILENAME != lastfile { + if (lastfile) + check_one(lastfile); + lastfile = FILENAME; +} + +index ($0, "Displaying notes") != 0 { sanity = 1 } +index ($0, "IBT") != 0 && index ($0, "SHSTK") != 0 { cet = 1 } + +END { + check_one(lastfile); + exit(result); +} diff --git a/sysdeps/unix/sysv/linux/x86/configure b/sysdeps/unix/sysv/linux/x86/configure new file mode 100644 index 0000000000..18ba7af034 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/configure @@ -0,0 +1,72 @@ +# This file is generated from configure.ac by Autoconf. DO NOT EDIT! + # Local configure fragment for sysdeps/unix/sysv/linux/x86. + +if test x"$enable_cet" = xdefault || test x"$enable_cet" = xyes; then + # Check if CET can be enabled. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CET can be enabled" >&5 +$as_echo_n "checking whether CET can be enabled... " >&6; } +if ${libc_cv_x86_cet_available+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat > conftest.c <&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + libc_cv_x86_cet_available=yes + else + libc_cv_x86_cet_available=no + fi + rm -rf conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_x86_cet_available" >&5 +$as_echo "$libc_cv_x86_cet_available" >&6; } + if test $libc_cv_x86_cet_available = yes; then + enable_cet=yes + else + if test x"$enable_cet" = xdefault; then + enable_cet=no + else + as_fn_error $? "$CC doesn't support CET" "$LINENO" 5 + fi + fi +fi +if test $enable_cet = yes; then + # Check if assembler supports CET. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $AS supports CET" >&5 +$as_echo_n "checking whether $AS supports CET... " >&6; } +if ${libc_cv_x86_cet_as+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat > conftest.s <&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + libc_cv_x86_cet_as=yes + else + libc_cv_x86_cet_as=no + fi + rm -rf conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_x86_cet_as" >&5 +$as_echo "$libc_cv_x86_cet_as" >&6; } + if test $libc_cv_x86_cet_as = no; then + as_fn_error $? "$AS doesn't support CET" "$LINENO" 5 + fi + +$as_echo "#define ENABLE_CET 1" >>confdefs.h + +fi +config_vars="$config_vars +enable-cet = $enable_cet" diff --git a/sysdeps/unix/sysv/linux/x86/configure.ac b/sysdeps/unix/sysv/linux/x86/configure.ac new file mode 100644 index 0000000000..7ef9fbe1de --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/configure.ac @@ -0,0 +1,48 @@ +GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. +# Local configure fragment for sysdeps/unix/sysv/linux/x86. + +if test x"$enable_cet" = xdefault || test x"$enable_cet" = xyes; then + # Check if CET can be enabled. + AC_CACHE_CHECK(whether CET can be enabled, + libc_cv_x86_cet_available, [dnl +cat > conftest.c <&AS_MESSAGE_LOG_FD); then + libc_cv_x86_cet_available=yes + else + libc_cv_x86_cet_available=no + fi + rm -rf conftest*]) + if test $libc_cv_x86_cet_available = yes; then + enable_cet=yes + else + if test x"$enable_cet" = xdefault; then + enable_cet=no + else + AC_MSG_ERROR([$CC doesn't support CET]) + fi + fi +fi +if test $enable_cet = yes; then + # Check if assembler supports CET. + AC_CACHE_CHECK(whether $AS supports CET, + libc_cv_x86_cet_as, [dnl +cat > conftest.s <&AS_MESSAGE_LOG_FD); then + libc_cv_x86_cet_as=yes + else + libc_cv_x86_cet_as=no + fi + rm -rf conftest*]) + if test $libc_cv_x86_cet_as = no; then + AC_MSG_ERROR([$AS doesn't support CET]) + fi + AC_DEFINE(ENABLE_CET, 1, + [Enable Intel Control-flow Enforcement Technology (CET)]) +fi +LIBC_CONFIG_VAR([enable-cet], [$enable_cet]) diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.c b/sysdeps/unix/sysv/linux/x86/dl-cet.c new file mode 100644 index 0000000000..e8b12d0fe2 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/dl-cet.c @@ -0,0 +1,88 @@ +/* Linux/x86 CET initializers function. + Copyright (C) 2017 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef SHARED +# include + +# ifndef LINKAGE +# define LINKAGE +# endif + +LINKAGE +void +_dl_cet_init (struct link_map *main_map, int argc, char **argv, char **env) +{ + /* Check if IBT is enabled in executable. */ + bool enable_ibt + = ((GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) + && (main_map->l_cet & lc_ibt)); + + /* Check if SHSTK is enabled in executable. */ + bool enable_shstk + = ((GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) + && (main_map->l_cet & lc_shstk)); + + if (enable_ibt || enable_shstk) + { + unsigned int i; + struct link_map *l; + + i = main_map->l_searchlist.r_nlist; + while (i-- > 0) + { + /* Check each shared object to see if IBT and SHSTK are + enabled. */ + l = main_map->l_initfini[i]; + + /* Skip CET check for ld.so since ld.so is CET-enabled. */ + if (l == &GL(dl_rtld_map)) + continue; + + if (enable_ibt && !(l->l_cet & lc_ibt)) + { + /* If IBT is enabled in executable and IBT isn't enabled in + this shard object, put all executable PT_LOAD segments + in legacy code page bitmap. */ + + /* FIXME: Mark legacy region */ + } + + /* SHSTK is enabled only if it is enabled in executable as + well as all shared objects. */ + enable_shstk = !!(l->l_cet & lc_shstk); + + /* Stop if both IBT and SHSTCK are disabled. */ + if (!enable_ibt && !enable_shstk) + break; + } + } + + if (!enable_ibt || !enable_shstk) + { + /* FIXME: Disable IBT and/or SHSTK. */ + ; + } + + if (enable_ibt || enable_shstk) + { + /* FIXME: Lock CET if IBT or SHSTK is enabled. */ + ; + } + + _dl_init (main_map, argc, argv, env); +} +#endif diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.h b/sysdeps/unix/sysv/linux/x86/dl-cet.h new file mode 100644 index 0000000000..5758cdf05a --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h @@ -0,0 +1,125 @@ +/* Linux/x86 CET inline functions. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _dl_cet_h +#define _dl_cet_h + +extern void _dl_cet_init (struct link_map *, int, char **, char **) + attribute_hidden; + +#define DL_INIT "_dl_cet_init" + +#ifdef ElfW +static inline void __attribute__ ((unused)) +dl_process_cet_property_note (struct link_map *l, + const ElfW(Nhdr) *note, + const ElfW(Addr) size, + const ElfW(Addr) align) +{ + /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in + 32-bit objects and to 8 bytes in 64-bit objects. Skip notes + with incorrect alignment. */ + if (align != (__ELF_NATIVE_CLASS / 8)) + return; + + const ElfW(Addr) start = (ElfW(Addr)) note; + + while ((ElfW(Addr)) (note + 1) - start < size) + { + /* Find the NT_GNU_PROPERTY_TYPE_0 note. */ + if (note->n_namesz == 4 + && note->n_type == NT_GNU_PROPERTY_TYPE_0 + && memcmp (note + 1, "GNU", 4) == 0) + { + /* Check for invalid property. */ + if (note->n_descsz < 8 + || (note->n_descsz % sizeof (ElfW(Addr))) != 0) + break; + + /* Start and end of property array. */ + unsigned char *ptr = (unsigned char *) (note + 1) + 4; + unsigned char *ptr_end = ptr + note->n_descsz; + + while (1) + { + unsigned int type = *(unsigned int *) ptr; + unsigned int datasz = *(unsigned int *) (ptr + 4); + + ptr += 8; + if ((ptr + datasz) > ptr_end) + break; + + if (type == GNU_PROPERTY_X86_FEATURE_1_AND + && datasz == 4) + { + unsigned int feature_1 = *(unsigned int *) ptr; + if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) + l->l_cet |= lc_ibt; + if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) + l->l_cet |= lc_shstk; + break; + } + } + } + + /* NB: Note sections like .note.ABI-tag and .note.gnu.build-id are + aligned to 4 bytes in 64-bit ELF objects. */ + note = ((const void *) note + + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz, + align)); + } +} + +# ifdef FILEBUF_SIZE +# define DL_PROCESS_PT_NOTE(l, ph, fd, fbp) \ + dl_process_pt_note ((l), (ph), (fd), (fbp)) + +static inline int __attribute__ ((unused)) +dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph, + int fd, struct filebuf *fbp) +{ + const ElfW(Nhdr) *note; + ElfW(Addr) size = ph->p_filesz; + + if (ph->p_offset + size <= (size_t) fbp->len) + note = (const void *) (fbp->buf + ph->p_offset); + else + { + note = alloca (size); + __lseek (fd, ph->p_offset, SEEK_SET); + if (__libc_read (fd, (void *) note, size) != size) + return -1; + } + + dl_process_cet_property_note (l, note, size, ph->p_align); + return 0; +} +# else +# define DL_PROCESS_PT_NOTE(l, ph) dl_process_pt_note ((l), (ph)) + +static inline int __attribute__ ((unused)) +dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) +{ + const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr); + dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align); + return 0; +} +# endif +#endif + +#endif /* _dl_cet_h */ diff --git a/sysdeps/unix/sysv/linux/x86/dl-procruntime.c b/sysdeps/unix/sysv/linux/x86/dl-procruntime.c new file mode 100644 index 0000000000..17c354684c --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/dl-procruntime.c @@ -0,0 +1,57 @@ +/* Data for processor runtime information. Linux/x86 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This information must be kept in sync with the _DL_HWCAP_COUNT, + HWCAP_PLATFORMS_START and HWCAP_PLATFORMS_COUNT definitions in + dl-hwcap.h. + + If anything should be added here check whether the size of each string + is still ok with the given array size. + + All the #ifdefs in the definitions are quite irritating but + necessary if we want to avoid duplicating the information. There + are three different modes: + + - PROCINFO_DECL is defined. This means we are only interested in + declarations. + + - PROCINFO_DECL is not defined: + + + if SHARED is defined the file is included in an array + initializer. The .element = { ... } syntax is needed. + + + if SHARED is not defined a normal array initialization is + needed. + */ + +#ifndef PROCINFO_CLASS +# define PROCINFO_CLASS +#endif + +#if !IS_IN (ldconfig) +# if !defined PROCINFO_DECL && defined SHARED + ._dl_x86_feature_1 +# else +PROCINFO_CLASS unsigned int _dl_x86_feature_1 +# endif +# if !defined SHARED || defined PROCINFO_DECL +; +# else +, +# endif +#endif diff --git a/sysdeps/unix/sysv/linux/x86/ldsodefs.h b/sysdeps/unix/sysv/linux/x86/ldsodefs.h new file mode 100644 index 0000000000..0c40edd9a2 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/ldsodefs.h @@ -0,0 +1,60 @@ +/* Run-time dynamic linker data structures for x86 loaded ELF shared objects. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LDSODEFS_H + +/* Get the real definitions. */ +#include_next + +#if defined ENABLE_CET && defined N_ && !IS_IN (ldconfig) +# include + +# define DL_OPEN_CHECK dl_cet_open_check + +static inline void __attribute__ ((unused)) +dl_cet_open_check (struct link_map *l) +{ + int res; + + /* Check IBT and SHSTK when called from dlopen. */ + if ((GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_IBT) + && !(l->l_cet & lc_ibt)) + { + /* If IBT is enabled in executable and IBT isn't enabled in + this shared object, put all executable PT_LOAD segments in + legacy code page bitmap. */ + /* FIXME: Mark legacy region. */ + res = -EINVAL; + goto cet_check_failure; + } + + /* If SHSTK is enabled in executable and SHSTK isn't enabled in + this shared object, we can't load this shared object. */ + if ((GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) + && !(l->l_cet & lc_shstk)) + { + res = -EINVAL; + +cet_check_failure: + _dl_signal_error (-res, "dlopen", NULL, + N_("dl_cet_open_check failed")); + } +} +#endif + +#endif /* ldsodefs.h */ diff --git a/sysdeps/unix/sysv/linux/x86/link_map.h b/sysdeps/unix/sysv/linux/x86/link_map.h new file mode 100644 index 0000000000..86e098e4a5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/link_map.h @@ -0,0 +1,26 @@ +/* Additional fields in struct link_map. Linux/x86 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* If this object is enabled with CET. */ +enum + { + lc_none = 0, /* Not enabled with CET. */ + lc_ibt = 1 << 0, /* Enabled with IBT. */ + lc_shstk = 1 << 1, /* Enabled with STSHK. */ + lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */ + } l_cet:2; diff --git a/sysdeps/unix/sysv/linux/x86/stdlib/ucontext.h b/sysdeps/unix/sysv/linux/x86/stdlib/ucontext.h new file mode 100644 index 0000000000..228f10d705 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/stdlib/ucontext.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/unix/sysv/linux/x86/tst-setcontext3-shstk.sh b/sysdeps/unix/sysv/linux/x86/tst-setcontext3-shstk.sh new file mode 100755 index 0000000000..7598584fb0 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/tst-setcontext3-shstk.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Check that GNU_PROPERTY_X86_FEATURE_1_SHSTK isn't set when setcontext() +# is used. +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +set -e + +objpfx=$1 +readelf=$2 + +test="${objpfx}tst-setcontext3" + +if $readelf -n $test | grep SHSTK; then + echo "FAIL: GNU_PROPERTY_X86_FEATURE_1_SHSTK is set on tst-setcontext3" + exit 1 +else + echo "PASS: GNU_PROPERTY_X86_FEATURE_1_SHSTK isn't set on tst-setcontext3" + exit 0 +fi diff --git a/sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c b/sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c new file mode 100644 index 0000000000..ac31994251 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/tst-ucontext-1.c @@ -0,0 +1,20 @@ +/* Check for error with -fcf-protection -mshstk on makecontext family + functions. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include diff --git a/sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh b/sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh new file mode 100755 index 0000000000..3ea88f7d6d --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/tst-ucontext-1.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Check for error with -fcf-protection -mshstk on makecontext family +# functions. +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +set -e + +CC=$1 +CFLAGS=$2 +shift 2 + +rc=0 +for src in $*; do + if $CC $CFLAGS $CPPFLAGS -fcf-protection -mshstk -S $src -o /dev/null 2>&1; then + echo "FAIL: No error on $src with -fcf-protection -mshstk" + rc=1 + else + echo "PASS: Error on $src with -fcf-protection -mshstk" + fi +done + +exit $rc diff --git a/sysdeps/unix/sysv/linux/x86/ucontext.h b/sysdeps/unix/sysv/linux/x86/ucontext.h new file mode 100644 index 0000000000..f25dbb98dc --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/ucontext.h @@ -0,0 +1,56 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* System V ABI compliant user-level context switching support. */ + +#ifndef _UCONTEXT_H +#define _UCONTEXT_H 1 + +#include + +#if defined(__SHSTK__) && !defined(_LIBC) +# error -mshstk incompatible with ucontext.h APIs +#endif + +/* Get machine dependent definition of data structures. */ +#include + +__BEGIN_DECLS + +/* Get user context and store it in variable pointed to by UCP. */ +extern int getcontext (ucontext_t *__ucp) __THROWNL; + +/* Set user context from information of variable pointed to by UCP. */ +extern int setcontext (const ucontext_t *__ucp) __THROWNL; + +/* Save current context in context variable pointed to by OUCP and set + context from variable pointed to by UCP. */ +extern int swapcontext (ucontext_t *__restrict __oucp, + const ucontext_t *__restrict __ucp) __THROWNL; + +/* Manipulate user context UCP to continue with calling functions FUNC + and the ARGC-1 parameters following ARGC when the context is used + the next time in `setcontext' or `swapcontext'. + + We cannot say anything about the parameters FUNC takes; `void' + is as good as any other choice. */ +extern void makecontext (ucontext_t *__ucp, void (*__func) (void), + int __argc, ...) __THROW; + +__END_DECLS + +#endif /* ucontext.h */ diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-machine.h b/sysdeps/unix/sysv/linux/x86_64/dl-machine.h new file mode 100644 index 0000000000..add79e9a1c --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/dl-machine.h @@ -0,0 +1,27 @@ +/* Machine-dependent ELF dynamic relocation inline functions. + Linux/x86-64 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef ENABLE_CET +# include +#endif +#ifdef __ILP32__ +# include +#else +# include +#endif diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h index b7f7898d11..187a8a5a42 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/cpu-features.h @@ -158,6 +158,11 @@ struct cpu_features extern const struct cpu_features *__get_cpu_features (void) __attribute__ ((const)); +# ifdef ElfW +extern void _dl_setup_cet (const ElfW(Phdr) *, size_t, const ElfW(Addr)) + attribute_hidden; +# endif + # if defined (_LIBC) && !IS_IN (nonlib) /* Unused for x86. */ # define INIT_ARCH() diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h index eb25e4b658..7fc271570a 100644 --- a/sysdeps/x86/sysdep.h +++ b/sysdeps/x86/sysdep.h @@ -25,6 +25,10 @@ /* Syntactic details of assembler. */ +#ifndef _CET_ENDBR +# define _CET_ENDBR +#endif + /* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ #define ALIGNARG(log2) 1<