@@ -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
@@ -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.
@@ -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.
@@ -30,6 +30,32 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
+
+/* 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 <abi-tag.h>
#include <stackinfo.h>
@@ -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))
@@ -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);
@@ -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
@@ -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\
@@ -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
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef SHARED
+# define LINKAGE static inline
+# define _dl_cet_init cet_init
+# include <sysdeps/unix/sysv/linux/x86/dl-cet.c>
+# 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
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef ENABLE_CET
+# include <sysdeps/unix/sysv/linux/x86/dl-cet.h>
+#endif
+#include <sysdeps/i386/dl-machine.h>
@@ -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 <cet.h> 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
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -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 <<EOF
+#if !defined __IBT__ || !defined __SHSTK__
+# error CET isn't available.
+#endif
+EOF
+ if { ac_try='${CC-cc} -c $CFLAGS -fcf-protection -mcet -include cet.h conftest.c 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&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 <<EOF
+ incsspd %ecx
+EOF
+ if { ac_try='${CC-cc} -c $CFLAGS conftest.s -o conftest.o 1>&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&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"
new file mode 100644
@@ -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 <<EOF
+#if !defined __IBT__ || !defined __SHSTK__
+# error CET isn't available.
+#endif
+EOF
+ if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS -fcf-protection -mcet -include cet.h conftest.c 1>&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 <<EOF
+ incsspd %ecx
+EOF
+ if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s -o conftest.o 1>&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])
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef SHARED
+# include <ldsodefs.h>
+
+# 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
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#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 */
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LDSODEFS_H
+
+/* Get the real definitions. */
+#include_next <ldsodefs.h>
+
+#if defined ENABLE_CET && defined N_ && !IS_IN (ldconfig)
+# include <errno.h>
+
+# 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 */
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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;
new file mode 100644
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/x86/ucontext.h>
new file mode 100755
@@ -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
+# <http://www.gnu.org/licenses/>.
+
+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
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#include <ucontext.h>
new file mode 100755
@@ -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
+# <http://www.gnu.org/licenses/>.
+
+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
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+/* System V ABI compliant user-level context switching support. */
+
+#ifndef _UCONTEXT_H
+#define _UCONTEXT_H 1
+
+#include <features.h>
+
+#if defined(__SHSTK__) && !defined(_LIBC)
+# error -mshstk incompatible with ucontext.h APIs
+#endif
+
+/* Get machine dependent definition of data structures. */
+#include <sys/ucontext.h>
+
+__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 */
new file mode 100644
@@ -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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef ENABLE_CET
+# include <sysdeps/unix/sysv/linux/x86/dl-cet.h>
+#endif
+#ifdef __ILP32__
+# include <sysdeps/x86_64/x32/dl-machine.h>
+#else
+# include <sysdeps/x86_64/dl-machine.h>
+#endif
@@ -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()
@@ -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<<log2
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
@@ -36,6 +40,7 @@
.align ALIGNARG(4); \
C_LABEL(name) \
cfi_startproc; \
+ _CET_ENDBR; \
CALL_MCOUNT
#undef END
@@ -135,6 +135,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
return lazy;
}
+#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. */
@@ -176,7 +180,7 @@ _dl_start_user:\n\
# Clear %rbp to mark outermost frame obviously even for constructors.\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 %rdx, as per ELF ABI.\n\
leaq _dl_fini(%rip), %rdx\n\
# And make sure %rsp points to argc stored on the stack.\n\
@@ -64,6 +64,7 @@
cfi_startproc
_dl_runtime_resolve:
cfi_adjust_cfa_offset(16) # Incorporate PLT
+ _CET_ENDBR
# if DL_RUNTIME_RESOLVE_REALIGN_STACK
# if LOCAL_STORAGE_AREA != 8
# error LOCAL_STORAGE_AREA must be 8
@@ -168,6 +169,7 @@ _dl_runtime_resolve:
_dl_runtime_profile:
cfi_startproc
cfi_adjust_cfa_offset(16) # Incorporate PLT
+ _CET_ENDBR
/* The La_x86_64_regs data structure pointed to by the
fourth paramater must be VEC_SIZE-byte aligned. This must
be explicitly enforced. We have the set up a dynamically
@@ -73,7 +73,7 @@ _dl_start_user:\n\
# Clear %rbp to mark outermost frame obviously even for constructors.\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 %rdx, as per ELF ABI.\n\
lea _dl_fini(%rip), %edx\n\
# And make sure %rsp points to argc stored on the stack.\n\