aboutsummaryrefslogtreecommitdiff
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/linu