summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog67
-rwxr-xr-xconfigure11
-rw-r--r--configure.ac6
-rw-r--r--elf/Makefile2
-rw-r--r--elf/dl-load.c60
-rw-r--r--elf/dl-open.c3
-rw-r--r--elf/rtld.c9
-rw-r--r--sysdeps/generic/dl-prop.h54
-rw-r--r--sysdeps/i386/dl-cet.c67
-rw-r--r--sysdeps/i386/dl-trampoline.S72
-rw-r--r--sysdeps/unix/sysv/linux/x86/cpu-features.c38
-rw-r--r--sysdeps/unix/sysv/linux/x86/dl-cet.h37
-rw-r--r--sysdeps/x86/Makefile42
-rw-r--r--sysdeps/x86/cet-tunables.h29
-rw-r--r--sysdeps/x86/check-cet.awk53
-rw-r--r--sysdeps/x86/configure69
-rw-r--r--sysdeps/x86/configure.ac46
-rw-r--r--sysdeps/x86/cpu-features.c60
-rw-r--r--sysdeps/x86/cpu-tunables.c48
-rw-r--r--sysdeps/x86/dl-cet.c346
-rw-r--r--sysdeps/x86/dl-procruntime.c68
-rw-r--r--sysdeps/x86/dl-prop.h153
-rw-r--r--sysdeps/x86/dl-tunables.list6
-rw-r--r--sysdeps/x86/libc-start.h25
-rw-r--r--sysdeps/x86/link_map.h26
-rw-r--r--sysdeps/x86/sysdep.h8
-rw-r--r--sysdeps/x86_64/dl-trampoline.h2
27 files changed, 1382 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 65dd07f41c..05d05f7d41 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,70 @@
+2018-07-16  H.J. Lu  <hongjiu.lu@intel.com>
+
+	 [BZ #21598]
+	* configure.ac: Add --enable-cet.
+	* configure: Regenerated.
+	* elf/Makefille (all-built-dso): Add a comment.
+	* elf/dl-load.c (filebuf): Moved before "dynamic-link.h".
+	Include <dl-prop.h>.
+	(_dl_map_object_from_fd): Call _dl_process_pt_note on PT_NOTE
+	segment.
+	* elf/dl-open.c: Include <dl-prop.h>.
+	(dl_open_worker): Call _dl_open_check.
+	* elf/rtld.c: Include <dl-prop.h>.
+	(dl_main): Call _rtld_process_pt_note on PT_NOTE segment.  Call
+	_rtld_main_check.
+	* sysdeps/generic/dl-prop.h: New file.
+	* sysdeps/i386/dl-cet.c: Likewise.
+	* sysdeps/unix/sysv/linux/x86/cpu-features.c: Likewise.
+	* sysdeps/unix/sysv/linux/x86/dl-cet.h: Likewise.
+	* sysdeps/x86/cet-tunables.h: Likewise.
+	* sysdeps/x86/check-cet.awk: Likewise.
+	* sysdeps/x86/configure: Likewise.
+	* sysdeps/x86/configure.ac: Likewise.
+	* sysdeps/x86/dl-cet.c: Likewise.
+	* sysdeps/x86/dl-procruntime.c: Likewise.
+	* sysdeps/x86/dl-prop.h: Likewise.
+	* sysdeps/x86/libc-start.h: Likewise.
+	* sysdeps/x86/link_map.h: Likewise.
+	* 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/linux/x86/Makefile (sysdep-dl-routines): Add dl-cet
+	if CET is enabled.
+	(CFLAGS-.o): Add -fcf-protection if CET is enabled.
+	(CFLAGS-.os): Likewise.
+	(CFLAGS-.op): Likewise.
+	(CFLAGS-.oS): Likewise.
+	(asm-CPPFLAGS): Add -fcf-protection -include cet.h if CET
+	is enabled.
+	(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/cpu-features.c: Include <dl-cet.h> and
+	<cet-tunables.h>.
+	(TUNABLE_CALLBACK (set_x86_ibt)): New prototype.
+	(TUNABLE_CALLBACK (set_x86_shstk)): Likewise.
+	(init_cpu_features): Call get_cet_status to check CET status
+	and update dl_x86_feature_1 with CET status.  Call
+	TUNABLE_CALLBACK (set_x86_ibt) and TUNABLE_CALLBACK
+	(set_x86_shstk).  Disable and lock CET in libc.a.
+	* sysdeps/x86/cpu-tunables.c: Include <cet-tunables.h>.
+	(TUNABLE_CALLBACK (set_x86_ibt)): New function.
+	(TUNABLE_CALLBACK (set_x86_shstk)): Likewise.
+	* sysdeps/x86/sysdep.h (_CET_NOTRACK): New.
+	(_CET_ENDBR): Define if not defined.
+	(ENTRY): Add _CET_ENDBR.
+	* sysdeps/x86/dl-tunables.list (glibc.tune): Add x86_ibt and
+	x86_shstk.
+	* sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Add
+	_CET_ENDBR.
+	(_dl_runtime_profile): Likewise.
+
 2018-07-16  Rogerio A. Cardoso  <rcardoso@linux.vnet.ibm.com>
 
 	[BZ #21895]
diff --git a/configure b/configure
index eac7f292b4..fde57d63fe 100755
--- a/configure
+++ b/configure
@@ -790,6 +790,7 @@ enable_nscd
 enable_pt_chown
 enable_tunables
 enable_mathvec
+enable_cet
 with_cpu
 '
       ac_precious_vars='build_alias
@@ -1465,6 +1466,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]
@@ -3759,6 +3762,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=no
+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 f41ed6decb..014e09a5d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -464,6 +464,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=no])
+
 # 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/Makefile b/elf/Makefile
index 41cc3681be..84107f6dbb 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1058,6 +1058,8 @@ $(objpfx)tst-piemod1.so: $(libsupport)
 $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
 
 ifeq (yes,$(build-shared))
+# NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with
+# all-built-dso here.
 all-built-dso := $(common-objpfx)elf/ld.so $(common-objpfx)libc.so \
 		 $(filter-out $(common-objpfx)linkobj/libc.so, \
 			      $(sort $(wildcard $(addprefix $(common-objpfx), \
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 09185ab68d..c51e4b3718 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -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>
@@ -44,6 +70,7 @@
 #include <dl-unmap-segments.h>
 #include <dl-machine-reject-phdr.h>
 #include <dl-sysdep-open.h>
+#include <dl-prop.h>
 #include <not-cancel.h>
 
 #include <endian.h>
@@ -69,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;
 
@@ -1152,6 +1154,14 @@ _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;
+
+	case PT_NOTE:
+	  if (_dl_process_pt_note (l, ph, fd, fbp))
+	    {
+	      errstring = N_("cannot process note segment");
+	      goto call_lose;
+	    }
+	  break;
 	}
 
     if (__glibc_unlikely (nloadcmds == 0))
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 9dde4acfbc..f6c8ef1043 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -35,6 +35,7 @@
 #include <libc-internal.h>
 
 #include <dl-dst.h>
+#include <dl-prop.h>
 
 
 /* We must be careful not to leave us in an inconsistent state.  Thus we
@@ -291,6 +292,8 @@ dl_open_worker (void *a)
   _dl_debug_state ();
   LIBC_PROBE (map_complete, 3, args->nsid, r, new);
 
+  _dl_open_check (new);
+
   /* 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 8c732adb68..1b0c74739f 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -38,6 +38,7 @@
 #include <dl-cache.h>
 #include <dl-osinfo.h>
 #include <dl-procinfo.h>
+#include <dl-prop.h>
 #include <tls.h>
 #include <stap-probe.h>
 #include <stackinfo.h>
@@ -1241,6 +1242,12 @@ 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;
+
+      case PT_NOTE:
+	if (_rtld_process_pt_note (main_map, ph))
+	  _dl_error_printf ("\
+ERROR: '%s': cannot process note segment.\n", _dl_argv[0]);
+	break;
       }
 
   /* Adjust the address of the TLS initialization image in case
@@ -2110,6 +2117,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	_dl_show_scope (l, 0);
     }
 
+  _rtld_main_check (main_map, _dl_argv[0]);
+
   if (prelinked)
     {
       if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
diff --git a/sysdeps/generic/dl-prop.h b/sysdeps/generic/dl-prop.h
new file mode 100644
index 0000000000..a2b1d38c79
--- /dev/null
+++ b/sysdeps/generic/dl-prop.h
@@ -0,0 +1,54 @@
+/* Support for GNU properties.  Generic version.
+   Copyright (C) 2018 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_PROP_H
+#define _DL_PROP_H
+
+/* The following functions are used by the dynamic loader and the
+   dlopen machinery to process PT_NOTE entries in the binary or
+   shared object.  The notes can be used to change the behaviour of
+   the loader, and as such offer a flexible mechanism for hooking in
+   various checks related to ABI tags or implementing "flag day" ABI
+   transitions.  */
+
+static inline void __attribute__ ((always_inline))
+_rtld_main_check (struct link_map *m, const char *program)
+{
+}
+
+static inline void __attribute__ ((always_inline))
+_dl_open_check (struct link_map *m)
+{
+}
+
+#ifdef FILEBUF_SIZE
+static inline int __attribute__ ((always_inline))
+_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
+		     int fd, struct filebuf *fbp)
+{
+  return 0;
+}
+#endif
+
+static inline int __attribute__ ((always_inline))
+_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
+{
+  return 0;
+}
+
+#endif /* _DL_PROP_H */
diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c
new file mode 100644
index 0000000000..5d9a4e8d51
--- /dev/null
+++ b/sysdeps/i386/dl-cet.c
@@ -0,0 +1,67 @@
+/* Linux/i386 CET initializers function.
+   Copyright (C) 2018 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/>.  */
+
+
+#define LINKAGE static inline
+#define _dl_cet_check cet_check
+#include <sysdeps/x86/dl-cet.c>
+#undef _dl_cet_check
+
+#ifdef SHARED
+void
+_dl_cet_check (struct link_map *main_map, const char *program)
+{
+  cet_check (main_map, program);
+
+  if ((GL(dl_x86_feature_1)[0] & 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/i386/dl-trampoline.S b/sysdeps/i386/dl-trampoline.S
index 8bf86f8fd9..6dc0319216 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/x86/cpu-features.c b/sysdeps/unix/sysv/linux/x86/cpu-features.c
new file mode 100644
index 0000000000..7c9df9b794
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/cpu-features.c
@@ -0,0 +1,38 @@
+/* Initialize CPU feature data for Linux/x86.
+   This file is part of the GNU C Library.
+   Copyright (C) 2018 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/>.  */
+
+#if CET_ENABLED
+static inline int __attribute__ ((always_inline))
+get_cet_status (void)
+{
+  return 0;
+}
+
+# ifndef SHARED
+static inline void
+x86_setup_tls (void)
+{
+  __libc_setup_tls ();
+  THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)[0]);
+}
+
+#  define ARCH_SETUP_TLS() x86_setup_tls ()
+# endif
+#endif
+
+#include <sysdeps/x86/cpu-features.c>
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..ae81e2f2ca
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h
@@ -0,0 +1,37 @@
+/* Linux/x86 CET initializers function.
+   Copyright (C) 2018 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/>.  */
+
+static inline int __attribute__ ((always_inline))
+dl_cet_allocate_legacy_bitmap (unsigned long *legacy_bitmap)
+{
+  /* FIXME: Need syscall support.  */
+  return -1;
+}
+
+static inline int __attribute__ ((always_inline))
+dl_cet_disable_cet (unsigned int cet_feature)
+{
+  /* FIXME: Need syscall support.  */
+  return -1;
+}
+
+static inline int __attribute__ ((always_inline))
+dl_cet_lock_cet (void)
+{
+  /* FIXME: Need syscall support.  */
+  return -1;
+}
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 65292f4032..e9b2d0b35d 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -13,3 +13,45 @@ ifeq ($(subdir),setjmp)
 gen-as-const-headers += jmp_buf-ssp.sym
 sysdep_routines += __longjmp_cancel
 endif
+
+ifeq ($(enable-cet),yes)
+ifeq ($(subdir),elf)
+sysdep-dl-routines += dl-cet
+endif
+
+# Add -fcf-protection to CFLAGS when CET is enabled.
+CFLAGS-.o += -fcf-protection
+CFLAGS-.os += -fcf-protection
+CFLAGS-.op += -fcf-protection
+CFLAGS-.oS += -fcf-protection
+
+# Compile assembly codes with <cet.h> when CET is enabled.
+asm-CPPFLAGS += -fcf-protection -include cet.h
+
+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/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/x86/cet-tunables.h b/sysdeps/x86/cet-tunables.h
new file mode 100644
index 0000000000..ca023053ee
--- /dev/null
+++ b/sysdeps/x86/cet-tunables.h
@@ -0,0 +1,29 @@
+/* x86 CET tuning.
+   This file is part of the GNU C Library.
+   Copyright (C) 2018 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/>.  */
+
+/* Valid control values:
+   0: Enable CET features based on ELF property note.
+   1: Always disable CET features.
+   2: Always enable CET features.
+   3: Enable CET features permissively.
+ */
+#define CET_ELF_PROPERTY	0
+#define CET_ALWAYS_OFF		1
+#define CET_ALWAYS_ON		2
+#define CET_PERMISSIVE		3
+#define CET_MAX			CET_PERMISSIVE
diff --git a/sysdeps/x86/check-cet.awk b/sysdeps/x86/check-cet.awk
new file mode 100644
index 0000000000..380d998caf
--- /dev/null
+++ b/sysdeps/x86/check-cet.awk
@@ -0,0 +1,53 @@
+# Verify that all shared objects contain the CET property.
+# Copyright (C) 2018 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 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/x86/configure b/sysdeps/x86/configure
new file mode 100644
index 0000000000..b1ff281249
--- /dev/null
+++ b/sysdeps/x86/configure
@@ -0,0 +1,69 @@
+# This file is generated from configure.ac by Autoconf.  DO NOT EDIT!
+ # Local configure fragment for sysdeps/x86.
+
+if 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 __CET__ || __CET__ != 3
+# error CET isn't available.
+#endif
+EOF
+		 if { ac_try='${CC-cc} -c $CFLAGS -fcf-protection -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
+fi
+config_vars="$config_vars
+enable-cet = $enable_cet"
diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac
new file mode 100644
index 0000000000..a909b073af
--- /dev/null
+++ b/sysdeps/x86/configure.ac
@@ -0,0 +1,46 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/x86.
+
+if 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 __CET__ || __CET__ != 3
+# error CET isn't available.
+#endif
+EOF
+		 if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS -fcf-protection -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
+fi
+LIBC_CONFIG_VAR([enable-cet], [$enable_cet])
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index d41ebde823..0627f145e0 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -28,6 +28,15 @@
 
 extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *)
   attribute_hidden;
+
+# if CET_ENABLED
+#  include <dl-cet.h>
+#  include <cet-tunables.h>
+extern void TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *)
+  attribute_hidden;
+extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *)
+  attribute_hidden;
+# endif
 #endif
 
 static void
@@ -449,4 +458,55 @@ no_cpuid:
   else if (CPU_FEATURES_ARCH_P (cpu_features, I586))
     GLRO(dl_platform) = "i586";
 #endif
+
+#if CET_ENABLED
+# if HAVE_TUNABLES
+  TUNABLE_GET (x86_ibt, tunable_val_t *,
+	       TUNABLE_CALLBACK (set_x86_ibt));
+  TUNABLE_GET (x86_shstk, tunable_val_t *,
+	       TUNABLE_CALLBACK (set_x86_shstk));
+# endif
+
+  /* Check CET status.  */
+  unsigned int cet_status = get_cet_status ();
+
+  if (cet_status)
+    {
+      GL(dl_x86_feature_1)[0] = cet_status;
+
+# ifndef SHARED
+      /* Check if IBT and SHSTK are enabled by kernel.  */
+      if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_IBT)
+	  || (cet_status & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
+	{
+	  /* Disable IBT and/or SHSTK if they are enabled by kernel, but
+	     disabled by environment variable:
+
+	     GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
+	   */
+	  unsigned int cet_feature = 0;
+	  if (!HAS_CPU_FEATURE (IBT))
+	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+	  if (!HAS_CPU_FEATURE (SHSTK))
+	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+
+	  if (cet_feature)
+	    {
+	      int res = dl_cet_disable_cet (cet_feature);
+
+	      /* Clear the disabled bits in dl_x86_feature_1.  */
+	      if (res == 0)
+		GL(dl_x86_feature_1)[0] &= ~cet_feature;
+	    }
+
+	  /* Lock CET if IBT or SHSTK is enabled in executable.  Don't
+	     lock CET if SHSTK is enabled permissively.  */
+	  if (((GL(dl_x86_feature_1)[1] >> CET_MAX)
+	       & ((1 << CET_MAX) - 1))
+	       != CET_PERMISSIVE)
+	    dl_cet_lock_cet ();
+	}
+# endif
+    }
+#endif
 }
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index af761dcbbc..69155a8f44 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -334,4 +334,52 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
     }
   while (*p != '\0');
 }
+
+# if CET_ENABLED
+#  include <cet-tunables.h>
+
+attribute_hidden
+void
+TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *valp)
+{
+  if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
+    {
+      GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1);
+      GL(dl_x86_feature_1)[1] |= CET_ALWAYS_ON;
+    }
+  else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
+    {
+      GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1);
+      GL(dl_x86_feature_1)[1] |= CET_ALWAYS_OFF;
+    }
+  else if (DEFAULT_MEMCMP (valp->strval, "permissive",
+			   sizeof ("permissive")) == 0)
+    {
+      GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1);
+      GL(dl_x86_feature_1)[1] |= CET_PERMISSIVE;
+    }
+}
+
+attribute_hidden
+void
+TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *valp)
+{
+  if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
+    {
+      GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX);
+      GL(dl_x86_feature_1)[1] |= (CET_ALWAYS_ON << CET_MAX);
+    }
+  else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
+    {
+      GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX);
+      GL(dl_x86_feature_1)[1] |= (CET_ALWAYS_OFF << CET_MAX);
+    }
+  else if (DEFAULT_MEMCMP (valp->strval, "permissive",
+			   sizeof ("permissive")) == 0)
+    {
+      GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX);
+      GL(dl_x86_feature_1)[1] |= (CET_PERMISSIVE << CET_MAX);
+    }
+}
+# endif
 #endif
diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c
new file mode 100644
index 0000000000..b82ba14e75
--- /dev/null
+++ b/sysdeps/x86/dl-cet.c
@@ -0,0 +1,346 @@
+/* x86 CET initializers function.
+   Copyright (C) 2018 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/>.  */
+
+#include <unistd.h>
+#include <errno.h>
+#include <libintl.h>
+#include <ldsodefs.h>
+#include <dl-cet.h>
+#include <cet-tunables.h>
+
+/* GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK
+   are defined in <elf.h>, which are only available for C sources.
+   X86_FEATURE_1_IBT and X86_FEATURE_1_SHSTK are defined in <sysdep.h>
+   which are available for both C and asm sources.  They must match.   */
+#if GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
+# error GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
+#endif
+#if GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
+# error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
+#endif
+
+static int
+dl_cet_mark_legacy_region (struct link_map *l)
+{
+  /* Mark PT_LOAD segments with PF_X in legacy code page bitmap.  */
+  size_t i, phnum = l->l_phnum;
+  const ElfW(Phdr) *phdr = l->l_phdr;
+#ifdef __x86_64__
+  typedef unsigned long long word_t;
+#else
+  typedef unsigned long word_t;
+#endif
+  unsigned int bits_to_set;
+  word_t mask_to_set;
+#define BITS_PER_WORD (sizeof (word_t) * 8)
+#define BITMAP_FIRST_WORD_MASK(start) \
+  (~((word_t) 0) << ((start) & (BITS_PER_WORD - 1)))
+#define BITMAP_LAST_WORD_MASK(nbits) \
+  (~((word_t) 0) >> (-(nbits) & (BITS_PER_WORD - 1)))
+
+  word_t *bitmap = (word_t *) GL(dl_x86_legacy_bitmap)[0];
+  word_t bitmap_size = GL(dl_x86_legacy_bitmap)[1];
+  word_t *p;
+  size_t page_size = GLRO(dl_pagesize);
+
+  for (i = 0; i < phnum; i++)
+    if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X))
+      {
+	/* One bit in legacy bitmap represents a page.  */
+	ElfW(Addr) start = (phdr[i].p_vaddr + l->l_addr) / page_size;
+	ElfW(Addr) len = (phdr[i].p_memsz + page_size - 1) / page_size;
+	ElfW(Addr) end = start + len;
+
+	if ((end / 8) > bitmap_size)
+	  return -EINVAL;
+
+	p = bitmap + (start / BITS_PER_WORD);
+	bits_to_set = BITS_PER_WORD - (start % BITS_PER_WORD);
+	mask_to_set = BITMAP_FIRST_WORD_MASK (start);
+
+	while (len >= bits_to_set)
+	  {
+	    *p |= mask_to_set;
+	    len -= bits_to_set;
+	    bits_to_set = BITS_PER_WORD;
+	    mask_to_set = ~((word_t) 0);
+	    p++;
+	  }
+	if (len)
+	  {
+	    mask_to_set &= BITMAP_LAST_WORD_MASK (end);
+	    *p |= mask_to_set;
+	  }
+      }
+
+  return 0;
+}
+
+/* Check if object M is compatible with CET.  */
+
+static void
+dl_cet_check (struct link_map *m, const char *program)
+{
+  /* Check how IBT should be enabled.  */
+  unsigned int enable_ibt_type
+    = GL(dl_x86_feature_1)[1] & ((1 << CET_MAX) - 1);
+  /* Check how SHSTK should be enabled.  */
+  unsigned int enable_shstk_type
+    = ((GL(dl_x86_feature_1)[1] >> CET_MAX) & ((1 << CET_MAX) - 1));
+
+  /* No legacy object check if both IBT and SHSTK are always on.  */
+  if (enable_ibt_type == CET_ALWAYS_ON
+      && enable_shstk_type == CET_ALWAYS_ON)
+    return;
+
+  /* Check if IBT is enabled by kernel.  */
+  bool ibt_enabled
+    = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0;
+  /* Check if SHSTK is enabled by kernel.  */
+  bool shstk_enabled
+    = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
+
+  if (ibt_enabled || shstk_enabled)
+    {
+      struct link_map *l = NULL;
+
+      /* Check if IBT and SHSTK are enabled in object.  */
+      bool enable_ibt = (ibt_enabled
+			 && enable_ibt_type != CET_ALWAYS_OFF);
+      bool enable_shstk = (shstk_enabled
+			   && enable_shstk_type != CET_ALWAYS_OFF);
+      if (program)
+	{
+	  /* Enable IBT and SHSTK only if they are enabled in executable.
+	     NB: IBT and SHSTK may be disabled by environment variable:
+
+	     GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
+	   */
+	  enable_ibt &= (HAS_CPU_FEATURE (IBT)
+			 && (enable_ibt_type == CET_ALWAYS_ON
+			     || (m->l_cet & lc_ibt) != 0));
+	  enable_shstk &= (HAS_CPU_FEATURE (SHSTK)
+			   && (enable_shstk_type == CET_ALWAYS_ON
+			       || (m->l_cet & lc_shstk) != 0));
+	}
+
+      /* ld.so is CET-enabled by kernel.  But shared objects may not
+	 support IBT nor SHSTK.  */
+      if (enable_ibt || enable_shstk)
+	{
+	  int res;
+	  unsigned int i;
+	  unsigned int first_legacy, last_legacy;
+	  bool need_legacy_bitmap = false;
+
+	  i = m->l_searchlist.r_nlist;
+	  while (i-- > 0)
+	    {
+	      /* Check each shared object to see if IBT and SHSTK are
+		 enabled.  */
+	      l = m->l_initfini[i];
+
+	      if (l->l_init_called)
+		continue;
+
+#ifdef SHARED
+	      /* Skip CET check for ld.so since ld.so is CET-enabled.
+		 CET will be disabled later if CET isn't enabled in
+		 executable.  */
+	      if (l == &GL(dl_rtld_map)
+		  ||  l->l_real == &GL(dl_rtld_map)
+		  || (program && l == m))
+		continue;
+#endif
+
+	      if (enable_ibt
+		  && enable_ibt_type != CET_ALWAYS_ON
+		  && !(l->l_cet & lc_ibt))
+		{
+		  /* Remember the first and last legacy objects.  */
+		  if (!need_legacy_bitmap)
+		    last_legacy = i;
+		  first_legacy = i;
+		  need_legacy_bitmap = true;
+		}
+
+	      /* SHSTK is enabled only if it is enabled in executable as
+		 well as all shared objects.  */
+	      enable_shstk &= (enable_shstk_type == CET_ALWAYS_ON
+			       || (l->l_cet & lc_shstk) != 0);
+	    }
+
+	  if (need_legacy_bitmap)
+	    {
+	      if (GL(dl_x86_legacy_bitmap)[0])
+		{
+		  /* Change legacy bitmap to writable.  */
+		  if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0],
+				  GL(dl_x86_legacy_bitmap)[1],
+				  PROT_READ | PROT_WRITE) < 0)
+		    {
+mprotect_failure:
+		      if (program)
+			_dl_fatal_printf ("%s: mprotect legacy bitmap failed\n",
+					  l->l_name);
+		      else
+			_dl_signal_error (EINVAL, l->l_name, "dlopen",
+					  N_("mprotect legacy bitmap failed"));
+		    }
+		}
+	      else
+		{
+		  /* Allocate legacy bitmap.  */
+		  int res = dl_cet_allocate_legacy_bitmap
+		    (GL(dl_x86_legacy_bitmap));
+		  if (res != 0)
+		    {
+		      if (program)
+			_dl_fatal_printf ("%s: legacy bitmap isn't available\n",
+					  l->l_name);
+		      else
+			_dl_signal_error (EINVAL, l->l_name, "dlopen",
+					  N_("legacy bitmap isn't available"));
+		    }
+		}
+
+	      /* Put legacy shared objects in legacy bitmap.  */
+	      for (i = first_legacy; i <= last_legacy; i++)
+		{
+		  l = m->l_initfini[i];
+
+		  if (l->l_init_called || (l->l_cet & lc_ibt))
+		    continue;
+
+#ifdef SHARED
+		  if (l == &GL(dl_rtld_map)
+		      ||  l->l_real == &GL(dl_rtld_map)
+		      || (program && l == m))
+		    continue;
+#endif
+
+		  /* If IBT is enabled in executable and IBT isn't enabled
+		     in this shard object, mark PT_LOAD segments with PF_X
+		     in legacy code page bitmap.  */
+		  res = dl_cet_mark_legacy_region (l);
+		  if (res != 0)
+		    {
+		      if (program)
+			_dl_fatal_printf ("%s: failed to mark legacy code region\n",
+					  l->l_name);
+		      else
+			_dl_signal_error (-res, l->l_name, "dlopen",
+					  N_("failed to mark legacy code region"));
+		    }
+		}
+
+	      /* Change legacy bitmap to read-only.  */
+	      if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0],
+			      GL(dl_x86_legacy_bitmap)[1], PROT_READ) < 0)
+		goto mprotect_failure;
+	    }
+	}
+
+      bool cet_feature_changed = false;
+
+      if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
+	{
+	  if (!program
+	      && enable_shstk_type != CET_PERMISSIVE)
+	    {
+	      /* When SHSTK is enabled, we can't dlopening a shared
+		 object without SHSTK.  */
+	      if (enable_shstk != shstk_enabled)
+		_dl_signal_error (EINVAL, l->l_name, "dlopen",
+				  N_("shadow stack isn't enabled"));
+	      return;
+	    }
+
+	  /* Disable IBT and/or SHSTK if they are enabled by kernel, but
+	     disabled in executable or shared objects.  */
+	  unsigned int cet_feature = 0;
+
+	  /* Disable IBT only during program startup.  */
+	  if (program && !enable_ibt)
+	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+	  if (!enable_shstk)
+	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+
+	  int res = dl_cet_disable_cet (cet_feature);
+	  if (res != 0)
+	    {
+	      if (program)
+		_dl_fatal_printf ("%s: can't disable CET\n", program);
+	      else
+		_dl_signal_error (-res, l->l_name, "dlopen",
+				  N_("can't disable CET"));
+	    }
+
+	  /* Clear the disabled bits in dl_x86_feature_1.  */
+	  GL(dl_x86_feature_1)[0] &= ~cet_feature;
+
+	  cet_feature_changed = true;
+	}
+
+#ifdef SHARED
+      if (program
+	  && (!shstk_enabled
+	      || enable_shstk_type != CET_PERMISSIVE)
+	  && (ibt_enabled || shstk_enabled))
+	{
+	  /* Lock CET if IBT or SHSTK is enabled in executable.  Don't
+	     lock CET if SHSTK is enabled permissively.  */
+	  int res = dl_cet_lock_cet ();
+	  if (res != 0)
+	    _dl_fatal_printf ("%s: can't lock CET\n", program);
+
+	  cet_feature_changed = true;
+	}
+#endif
+
+      if (cet_feature_changed)
+	{
+	  unsigned int feature_1 = 0;
+	  if (enable_ibt)
+	    feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
+	  if (enable_shstk)
+	    feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+	  struct pthread *self = THREAD_SELF;
+	  THREAD_SETMEM (self, header.feature_1, feature_1);
+	}
+    }
+}
+
+void
+_dl_cet_open_check (struct link_map *l)
+{
+  dl_cet_check (l, NULL);
+}
+
+#ifdef SHARED
+
+# ifndef LINKAGE
+#  define LINKAGE
+# endif
+
+LINKAGE
+void
+_dl_cet_check (struct link_map *main_map, const char *program)
+{
+  dl_cet_check (main_map, program);
+}
+#endif /* SHARED */
diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c
new file mode 100644
index 0000000000..eddbde6a31
--- /dev/null
+++ b/sysdeps/x86/dl-procruntime.c
@@ -0,0 +1,68 @@
+/* Data for processor runtime information.  x86 version.
+   Copyright (C) 2018 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[2]
+# endif
+# if !defined SHARED || defined PROCINFO_DECL
+;
+# else
+,
+# endif
+
+# if !defined PROCINFO_DECL && defined SHARED
+  ._dl_x86_legacy_bitmap
+# else
+PROCINFO_CLASS unsigned long _dl_x86_legacy_bitmap[2]
+# endif
+# if !defined SHARED || defined PROCINFO_DECL
+;
+# else
+,
+# endif
+#endif
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
new file mode 100644
index 0000000000..d56e20a6dc
--- /dev/null
+++ b/sysdeps/x86/dl-prop.h
@@ -0,0 +1,153 @@
+/* Support for GNU properties.  x86 version.
+   Copyright (C) 2018 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_PROP_H
+#define _DL_PROP_H
+
+#include <not-cancel.h>
+
+extern void _dl_cet_check (struct link_map *, const char *)
+    attribute_hidden;
+extern void _dl_cet_open_check (struct link_map *)
+    attribute_hidden;
+
+static inline void __attribute__ ((always_inline))
+_rtld_main_check (struct link_map *m, const char *program)
+{
+#if CET_ENABLED
+  _dl_cet_check (m, program);
+#endif
+}
+
+static inline void __attribute__ ((always_inline))
+_dl_open_check (struct link_map *m)
+{
+#if CET_ENABLED
+  _dl_cet_open_check (m);
+#endif
+}
+
+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)
+{
+#if CET_ENABLED
+  /* 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));
+    }
+#endif
+}
+
+#ifdef FILEBUF_SIZE
+static inline int __attribute__ ((unused))
+_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
+		     int fd, struct filebuf *fbp)
+{
+# if CET_ENABLED
+  const ElfW(Nhdr) *note;
+  ElfW(Nhdr) *note_malloced = NULL;
+  ElfW(Addr) size = ph->p_filesz;
+
+  if (ph->p_offset + size <= (size_t) fbp->len)
+    note = (const void *) (fbp->buf + ph->p_offset);
+  else
+    {
+      if (size < __MAX_ALLOCA_CUTOFF)
+	note = alloca (size);
+      else
+	{
+	  note_malloced = malloc (size);
+	  note = note_malloced;
+	}
+      __lseek (fd, ph->p_offset, SEEK_SET);
+      if (__read_nocancel (fd, (void *) note, size) != size)
+	{
+	  if (note_malloced)
+	    free (note_malloced);
+	  return -1;
+	}
+    }
+
+  _dl_process_cet_property_note (l, note, size, ph->p_align);
+  if (note_malloced)
+    free (note_malloced);
+# endif
+  return 0;
+}
+#endif
+
+static inline int __attribute__ ((unused))
+_rtld_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 /* _DL_PROP_H */
diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list
index 7c3236a68f..73886b1352 100644
--- a/sysdeps/x86/dl-tunables.list
+++ b/sysdeps/x86/dl-tunables.list
@@ -21,6 +21,12 @@ glibc {
     hwcaps {
       type: STRING
     }
+    x86_ibt {
+      type: STRING
+    }
+    x86_shstk {
+      type: STRING
+    }
     x86_non_temporal_threshold {
       type: SIZE_T
     }
diff --git a/sysdeps/x86/libc-start.h b/sysdeps/x86/libc-start.h
new file mode 100644
index 0000000000..6f44262bf4
--- /dev/null
+++ b/sysdeps/x86/libc-start.h
@@ -0,0 +1,25 @@
+/* X86 definitions for libc main startup.
+   Copyright (C) 2018 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 SHARED
+# define ARCH_SETUP_IREL() apply_irel ()
+# define ARCH_APPLY_IREL()
+# ifndef ARCH_SETUP_TLS
+#  define ARCH_SETUP_TLS() __libc_setup_tls ()
+# endif
+#endif /* !SHARED */
diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h
new file mode 100644
index 0000000000..ef1206a9d2
--- /dev/null
+++ b/sysdeps/x86/link_map.h
@@ -0,0 +1,26 @@
+/* Additional fields in struct link_map.  Linux/x86 version.
+   Copyright (C) 2018 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;
diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h
index 976566aa37..8776ad8374 100644
--- a/sysdeps/x86/sysdep.h
+++ b/sysdeps/x86/sysdep.h
@@ -52,6 +52,13 @@ enum cf_protection_level
 
 /* Syntactic details of assembler.  */
 
+#ifdef _CET_ENDBR
+# define _CET_NOTRACK notrack
+#else
+# define _CET_ENDBR
+# define _CET_NOTRACK
+#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;
@@ -63,6 +70,7 @@ enum cf_protection_level
   .align ALIGNARG(4);							      \
   C_LABEL(name)								      \
   cfi_startproc;							      \
+  _CET_ENDBR;								      \
   CALL_MCOUNT
 
 #undef	END
diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h
index 298cfb3d99..a28b1e73a4 100644
--- a/sysdeps/x86_64/dl-trampoline.h
+++ b/sysdeps/x86_64/dl-trampoline.h
@@ -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