diff options
| -rw-r--r-- | ChangeLog | 67 | ||||
| -rwxr-xr-x | configure | 11 | ||||
| -rw-r--r-- | configure.ac | 6 | ||||
| -rw-r--r-- | elf/Makefile | 2 | ||||
| -rw-r--r-- | elf/dl-load.c | 60 | ||||
| -rw-r--r-- | elf/dl-open.c | 3 | ||||
| -rw-r--r-- | elf/rtld.c | 9 | ||||
| -rw-r--r-- | sysdeps/generic/dl-prop.h | 54 | ||||
| -rw-r--r-- | sysdeps/i386/dl-cet.c | 67 | ||||
| -rw-r--r-- | sysdeps/i386/dl-trampoline.S | 72 | ||||
| -rw-r--r-- | sysdeps/unix/sysv/linux/x86/cpu-features.c | 38 | ||||
| -rw-r--r-- | sysdeps/unix/sysv/linux/x86/dl-cet.h | 37 | ||||
| -rw-r--r-- | sysdeps/x86/Makefile | 42 | ||||
| -rw-r--r-- | sysdeps/x86/cet-tunables.h | 29 | ||||
| -rw-r--r-- | sysdeps/x86/check-cet.awk | 53 | ||||
| -rw-r--r-- | sysdeps/x86/configure | 69 | ||||
| -rw-r--r-- | sysdeps/x86/configure.ac | 46 | ||||
| -rw-r--r-- | sysdeps/x86/cpu-features.c | 60 | ||||
| -rw-r--r-- | sysdeps/x86/cpu-tunables.c | 48 | ||||
| -rw-r--r-- | sysdeps/x86/dl-cet.c | 346 | ||||
| -rw-r--r-- | sysdeps/x86/dl-procruntime.c | 68 | ||||
| -rw-r--r-- | sysdeps/x86/dl-prop.h | 153 | ||||
| -rw-r--r-- | sysdeps/x86/dl-tunables.list | 6 | ||||
| -rw-r--r-- | sysdeps/x86/libc-start.h | 25 | ||||
| -rw-r--r-- | sysdeps/x86/link_map.h | 26 | ||||
| -rw-r--r-- | sysdeps/x86/sysdep.h | 8 | ||||
| -rw-r--r-- | sysdeps/x86_64/dl-trampoline.h | 2 |
27 files changed, 1382 insertions, 25 deletions
@@ -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] @@ -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 |
