From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 53775 invoked by alias); 16 Jul 2018 18:34:02 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Received: (qmail 53738 invoked by uid 89); 16 Jul 2018 18:34:01 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.8 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_LAZY_DOMAIN_SECURITY,KAM_SHORT,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy=fourth, flexible, rm, hooking X-HELO: mail-qt0-f175.google.com Return-Path: From: Carlos O'Donell Subject: V3 [PATCH 03/24] x86: Support IBT and SHSTK in Intel CET [BZ #21598] To: "H.J. Lu" Cc: GNU C Library References: Message-ID: Date: Mon, 16 Jul 2018 18:34:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2018-07/txt/msg00458.txt.bz2 On 07/10/2018 06:09 PM, H.J. Lu wrote: > On Sat, Jul 7, 2018 at 1:01 PM, H.J. Lu wrote: >> On Fri, Jul 06, 2018 at 03:47:27PM -0400, Carlos O'Donell wrote: >>> On 06/13/2018 11:31 AM, H.J. Lu wrote: >>>> Intel Control-flow Enforcement Technology (CET) instructions: >>> Reviewed. >>> >>> Looking forward to v2. >>> > Here is V3. The difference from V2 is that get_cet_status became: > > static inline int __attribute__ ((always_inline)) > get_cet_status (void) > { > return 0; > } > Thank you for the update. With the following changes: - Add suggested comment to sysdeps/generic/dl-prop.h. - Make dl_cet_mark_legacy_region return -1 on error. - Fix typo s/fail/failed/g This version is OK. Reviewed-by: Carlos O'Donell > -- H.J. > > > 0003-x86-Support-IBT-and-SHSTK-in-Intel-CET-BZ-21598.patch > > > From b100bb5197020c403bf53f26b94324d04e4a0d45 Mon Sep 17 00:00:00 2001 > From: "H.J. Lu" > Date: Thu, 22 Jun 2017 04:15:39 -0700 > Subject: [PATCH 03/24] x86: Support IBT and SHSTK in Intel CET [BZ #21598] > > Intel Control-flow Enforcement Technology (CET) instructions: > > https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-en > forcement-technology-preview.pdf > > includes Indirect Branch Tracking (IBT) and Shadow Stack (SHSTK). > > GNU_PROPERTY_X86_FEATURE_1_IBT is added to GNU program property to > indicate that all executable sections are compatible with IBT when > ENDBR instruction starts each valid target where an indirect branch > instruction can land. Linker sets GNU_PROPERTY_X86_FEATURE_1_IBT on > output only if it is set on all relocatable inputs. > > On an IBT capable processor, the following steps should be taken: > > 1. When loading an executable without an interpreter, enable IBT and > lock IBT if GNU_PROPERTY_X86_FEATURE_1_IBT is set on the executable. > 2. When loading an executable with an interpreter, enable IBT if > GNU_PROPERTY_X86_FEATURE_1_IBT is set on the interpreter. > a. If GNU_PROPERTY_X86_FEATURE_1_IBT isn't set on the executable, > disable IBT. > b. Lock IBT. > 3. If IBT is enabled, when loading a shared object without > GNU_PROPERTY_X86_FEATURE_1_IBT: > a. If legacy interwork is allowed, then mark all pages in executable > PT_LOAD segments in legacy code page bitmap. Failure of legacy code > page bitmap allocation causes an error. > b. If legacy interwork isn't allowed, it causes an error. OK. > GNU_PROPERTY_X86_FEATURE_1_SHSTK is added to GNU program property to > indicate that all executable sections are compatible with SHSTK where > return address popped from shadow stack always matches return address > popped from normal stack. Linker sets GNU_PROPERTY_X86_FEATURE_1_SHSTK > on output only if it is set on all relocatable inputs. > > On a SHSTK capable processor, the following steps should be taken: > > 1. When loading an executable without an interpreter, enable SHSTK if > GNU_PROPERTY_X86_FEATURE_1_SHSTK is set on the executable. > 2. When loading an executable with an interpreter, enable SHSTK if > GNU_PROPERTY_X86_FEATURE_1_SHSTK is set on interpreter. > a. If GNU_PROPERTY_X86_FEATURE_1_SHSTK isn't set on the executable > or any shared objects loaded via the DT_NEEDED tag, disable SHSTK. > b. Otherwise lock SHSTK. > 3. After SHSTK is enabled, it is an error to load a shared object > without GNU_PROPERTY_X86_FEATURE_1_SHSTK. OK. > To enable CET support in glibc, --enable-cet is required to configure > glibc. When CET is enabled, both compiler and assembler must support > CET. Otherwise, it is a configure-time error. OK. > To support CET run-time control, > > 1. _dl_x86_feature_1 is added to the writable ld.so namespace to indicate > if IBT or SHSTK are enabled at run-time. It should be initialized by > init_cpu_features. > 2. For dynamic executables: > a. A l_cet field is added to struct link_map to indicate if IBT or > SHSTK is enabled in an ELF module. _dl_process_pt_note or > _rtld_process_pt_note is called to process PT_NOTE segment for > GNU program property and set l_cet. > b. _dl_open_check is added to check IBT and SHSTK compatibilty when > dlopening a shared object. > 3. Replace i386 _dl_runtime_resolve and _dl_runtime_profile with > _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, respectively if > SHSTK is enabled. OK. > CET run-time control can be changed via GLIBC_TUNABLES with > > $ export GLIBC_TUNABLES=glibc.tune.x86_shstk=[permissive|on|off] > $ export GLIBC_TUNABLES=glibc.tune.x86_ibt=[permissive|on|off] > OK. Thanks for using the x86_* prefix. I've started another thread to see if everyone wants to namespace per machine so we don't have name collisions. Using x86_* like you do here avoids any collisions. > 1. permissive: SHSTK is disabled when dlopening a legacy ELF module. > 2. on: IBT or SHSTK are always enabled, regardless if there are IBT or > SHSTK bits in GNU program property. > 3. off: IBT or SHSTK are always disabled, regardless if there are IBT or > SHSTK bits in GNU program property. > > from CET-enabled GCC is automatically included by assembly codes > to add GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK > to GNU program property. _CET_ENDBR is added at the entrance of all > assembly functions whose address may be taken. _CET_NOTRACK is used to > insert NOTRACK prefix with indirect jump table to support IBT. It is > defined as notrack when _CET_NOTRACK is defined in . > > [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_map_object_from_fd): Call _dl_process_pt_note on PT_NOTE > segment. > * elf/dl-open.c: Include . > (dl_open_worker): Call _dl_open_check. > * elf/rtld.c: Include . > (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 and > . > (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 . > (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. > --- > configure | 11 + > configure.ac | 6 + > elf/Makefile | 2 + > elf/dl-load.c | 60 ++-- > elf/dl-open.c | 3 + > elf/rtld.c | 9 + > sysdeps/generic/dl-prop.h | 47 +++ > sysdeps/i386/dl-cet.c | 67 +++++ > sysdeps/i386/dl-trampoline.S | 72 +++++ > sysdeps/unix/sysv/linux/x86/cpu-features.c | 38 +++ > sysdeps/unix/sysv/linux/x86/dl-cet.h | 34 +++ > sysdeps/x86/Makefile | 42 +++ > sysdeps/x86/cet-tunables.h | 29 ++ > sysdeps/x86/check-cet.awk | 53 ++++ > sysdeps/x86/configure | 69 +++++ > sysdeps/x86/configure.ac | 46 +++ > sysdeps/x86/cpu-features.c | 60 ++++ > sysdeps/x86/cpu-tunables.c | 48 +++ > sysdeps/x86/dl-cet.c | 335 +++++++++++++++++++++ > sysdeps/x86/dl-procruntime.c | 68 +++++ > sysdeps/x86/dl-prop.h | 153 ++++++++++ > sysdeps/x86/dl-tunables.list | 6 + > sysdeps/x86/libc-start.h | 25 ++ > sysdeps/x86/link_map.h | 26 ++ > sysdeps/x86/sysdep.h | 8 + > sysdeps/x86_64/dl-trampoline.h | 2 + > 26 files changed, 1294 insertions(+), 25 deletions(-) > create mode 100644 sysdeps/generic/dl-prop.h > create mode 100644 sysdeps/i386/dl-cet.c > create mode 100644 sysdeps/unix/sysv/linux/x86/cpu-features.c > create mode 100644 sysdeps/unix/sysv/linux/x86/dl-cet.h > create mode 100644 sysdeps/x86/cet-tunables.h > create mode 100644 sysdeps/x86/check-cet.awk > create mode 100644 sysdeps/x86/configure > create mode 100644 sysdeps/x86/configure.ac > create mode 100644 sysdeps/x86/dl-cet.c > create mode 100644 sysdeps/x86/dl-procruntime.c > create mode 100644 sysdeps/x86/dl-prop.h > create mode 100644 sysdeps/x86/libc-start.h > create mode 100644 sysdeps/x86/link_map.h > [snip configure] > 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]) > + OK. > # 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. OK. Perfect. Thanks for this. > 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 > #include > #include > + > +/* Type for the buffer we put the ELF header and hopefully the program > + header. This buffer does not really have to be too large. In most > + cases the program header follows the ELF header directly. If this > + is not the case all bets are off and we can make the header > + arbitrarily large and still won't get it read. This means the only > + question is how large are the ELF and program header combined. The > + ELF header 32-bit files is 52 bytes long and in 64-bit files is 64 > + bytes long. Each program header entry is again 32 and 56 bytes > + long respectively. I.e., even with a file which has 10 program > + header entries we only have to read 372B/624B respectively. Add to > + this a bit of margin for program notes and reading 512B and 832B > + for 32-bit and 64-bit files respecitvely is enough. If this > + heuristic should really fail for some file the code in > + `_dl_map_object_from_fd' knows how to recover. */ > +struct filebuf > +{ > + ssize_t len; > +#if __WORDSIZE == 32 > +# define FILEBUF_SIZE 512 > +#else > +# define FILEBUF_SIZE 832 > +#endif > + char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); > +}; > + OK. > #include "dynamic-link.h" > #include > #include > @@ -44,6 +70,7 @@ > #include > #include > #include > +#include > #include > > #include > @@ -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; OK. > } > > 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 > > #include > +#include OK. > > > /* 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); OK. Better. Less bitrot with unconditional calls like this. > + > /* 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 > #include > #include > +#include OK. > #include > #include > #include > @@ -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; OK. Thanks for the direct call. > } > > /* 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]); OK. Likewise. > + > 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..e5fe5d23aa > --- /dev/null > +++ b/sysdeps/generic/dl-prop.h > @@ -0,0 +1,47 @@ > +/* 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 > + . */ > + > +#ifndef _DL_PROP_H > +#define _DL_PROP_H > + Suggest adding the following comment: /* 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; > +} OK. > + > +#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 > + . */ > + > + > +#define LINKAGE static inline > +#define _dl_cet_check cet_check > +#include > +#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; > + } OK. > + > + 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; OK. > + } > + } > + } > +} OK. > +#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 OK. > 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 OK. > > #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 > + OK. > .globl _dl_runtime_profile > .type _dl_runtime_profile, @function > cfi_startproc > .align 16 > _dl_runtime_profile: > cfi_adjust_cfa_offset (8) > + _CET_ENDBR OK. > 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..0045f979da > --- /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 > + . */ > + > +#ifdef __CET__ > +static inline int __attribute__ ((always_inline)) > +get_cet_status (void) > +{ > + return 0; > +} Why is this still "return 0;" ? Is it because the kernel pieces aren't completely done yet and we'll enable this later? > + > +# 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 > + OK. > +#include > 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..9903bbe41f > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h > @@ -0,0 +1,34 @@ > +/* 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 > + . */ > + > +static inline int __attribute__ ((always_inline)) > +dl_cet_allocate_legacy_bitmap (unsigned long *legacy_bitmap) > +{ > + return -1; > +} > + > +static inline int __attribute__ ((always_inline)) > +dl_cet_disable_cet (unsigned int cet_feature) > +{ > + return -1; > +} > + > +static inline int __attribute__ ((always_inline)) > +dl_cet_lock_cet (void) > +{ > + return -1; > +} All three of these need comments explaining why they just return -1. Is it because it's a temporary implementation and the kernel pieces are not yet complete? It should say so then. > 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 OK. Inlcudes dl-cet.c code. > +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 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. OK. > +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 > + . */ > + > +/* 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 OK. > 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 > +# . > + > +# 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); > +} OK. > diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure [snipped] > 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 < +#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 < + 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]) OK. > diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c > index d41ebde823..f52e28e04b 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; > + > +# ifdef __CET__ > +# include > +# include > +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 OK. > #endif > > static void > @@ -449,4 +458,55 @@ no_cpuid: > else if (CPU_FEATURES_ARCH_P (cpu_features, I586)) > GLRO(dl_platform) = "i586"; > #endif > + > +#ifdef __CET__ > +# 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)); OK. > +# endif > + > + /* Check CET status. */ > + unsigned int cet_status = get_cet_status (); OK. > + > + 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 OK. > + */ > + 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 OK. > } > diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c > index af761dcbbc..a5c0153348 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'); > } > + > +# ifdef __CET__ > +# include > + > +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; > + } > +} OK. > + > +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); > + } > +} OK. > +# endif > #endif > diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c > new file mode 100644 > index 0000000000..5018e4560d > --- /dev/null > +++ b/sysdeps/x86/dl-cet.c > @@ -0,0 +1,335 @@ > +/* 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 > + . */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +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 -EFAULT; Why return -EFAULT? We only check != 0 in the caller, so just return -1? It may conuse things by using errno here, and worse negative errno. Please just return -1. > + > + 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; OK. > + 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; OK. > + } > + } > + > + 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: fail to mark legacy code region\n", s/fail/failed/g > + l->l_name); > + else > + _dl_signal_error (-res, l->l_name, "dlopen", > + N_("fail to mark legacy code region")); s/fail/failed/g > + } OK. > + } > + > + /* 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; > + } OK. > + > +#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 > + . */ > + > +/* 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 OK. > diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h > new file mode 100644 > index 0000000000..2709fe852d > --- /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 > + . */ > + > +#ifndef _DL_PROP_H > +#define _DL_PROP_H > + > +#include > + > +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) > +{ > +#ifdef __CET__ > + _dl_cet_check (m, program); > +#endif > +} OK. > + > +static inline void __attribute__ ((always_inline)) > +_dl_open_check (struct link_map *m) > +{ > +#ifdef __CET__ > + _dl_cet_open_check (m); > +#endif > +} OK. > + > +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) > +{ > +#ifdef __CET__ > + /* 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) OK. For the next arch that needs property handling we should genarlize some of these things in the future (not needed for 2.28). > + { > + /* 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) OK. > + { > + /* Check for invalid property. */ > + if (note->n_descsz < 8 > + || (note->n_descsz % sizeof (ElfW(Addr))) != 0) > + break; OK. > + > + /* 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) OK. > + { > + 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 > +} OK. > + > +#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) > +{ > +# ifdef __CET__ > + 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 OK. > + > +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; > +} OK. > + > +#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 > + } OK. > 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 > + . */ > + > +#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 */ OK. > 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 > + . */ > + > +/* 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; OK. > diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h > index afcb7cfd76..9843d9dff7 100644 > --- a/sysdeps/x86/sysdep.h > +++ b/sysdeps/x86/sysdep.h > @@ -25,6 +25,13 @@ > > /* Syntactic details of assembler. */ > > +#ifdef _CET_ENDBR > +# define _CET_NOTRACK notrack > +#else > +# define _CET_ENDBR > +# define _CET_NOTRACK > +#endif OK. > + > /* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ > #define ALIGNARG(log2) 1< #define ASM_SIZE_DIRECTIVE(name) .size name,.-name; > @@ -36,6 +43,7 @@ > .align ALIGNARG(4); \ > C_LABEL(name) \ > cfi_startproc; \ > + _CET_ENDBR; OK. \ > 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 > -- 2.17.1 OK. -- Cheers, Carlos.