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.

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.

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.

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.

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]

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.

<cet.h> 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 <cet.h>.

	 [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.
This commit is contained in:
H.J. Lu 2018-07-16 14:08:15 -07:00
parent 52b2a80fae
commit f753fa7dea
27 changed files with 1395 additions and 38 deletions

View File

@ -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]

11
configure vendored
View File

@ -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.

View File

@ -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.

View File

@ -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), \

View File

@ -30,44 +30,6 @@
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "dynamic-link.h"
#include <abi-tag.h>
#include <stackinfo.h>
#include <sysdep.h>
#include <stap-probe.h>
#include <libc-pointer-arith.h>
#include <array_length.h>
#include <dl-dst.h>
#include <dl-load.h>
#include <dl-map-segments.h>
#include <dl-unmap-segments.h>
#include <dl-machine-reject-phdr.h>
#include <dl-sysdep-open.h>
#include <not-cancel.h>
#include <endian.h>
#if BYTE_ORDER == BIG_ENDIAN
# define byteorder ELFDATA2MSB
#elif BYTE_ORDER == LITTLE_ENDIAN
# define byteorder ELFDATA2LSB
#else
# error "Unknown BYTE_ORDER " BYTE_ORDER
# define byteorder ELFDATANONE
#endif
#define STRING(x) __STRING (x)
int __stack_prot attribute_hidden attribute_relro
#if _STACK_GROWS_DOWN && defined PROT_GROWSDOWN
= PROT_GROWSDOWN;
#elif _STACK_GROWS_UP && defined PROT_GROWSUP
= PROT_GROWSUP;
#else
= 0;
#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
@ -94,6 +56,46 @@ struct filebuf
char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
};
#include "dynamic-link.h"
#include <abi-tag.h>
#include <stackinfo.h>
#include <sysdep.h>
#include <stap-probe.h>
#include <libc-pointer-arith.h>
#include <array_length.h>
#include <dl-dst.h>
#include <dl-load.h>
#include <dl-map-segments.h>
#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>
#if BYTE_ORDER == BIG_ENDIAN
# define byteorder ELFDATA2MSB
#elif BYTE_ORDER == LITTLE_ENDIAN
# define byteorder ELFDATA2LSB
#else
# error "Unknown BYTE_ORDER " BYTE_ORDER
# define byteorder ELFDATANONE
#endif
#define STRING(x) __STRING (x)
int __stack_prot attribute_hidden attribute_relro
#if _STACK_GROWS_DOWN && defined PROT_GROWSDOWN
= PROT_GROWSDOWN;
#elif _STACK_GROWS_UP && defined PROT_GROWSUP
= PROT_GROWSUP;
#else
= 0;
#endif
/* 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))

View File

@ -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);

View File

@ -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)

54
sysdeps/generic/dl-prop.h Normal file
View File

@ -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 */

67
sysdeps/i386/dl-cet.c Normal file
View File

@ -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

View File

@ -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

View File

@ -0,0 +1,38 @@
/* Initialize CPU feature data for Linux/x86.
This file is part of the GNU C Library.
Copyright (C) 2018 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#if CET_ENABLED
static inline int __attribute__ ((always_inline))
get_cet_status (void)
{
return 0;
}
# ifndef SHARED
static inline void
x86_setup_tls (void)
{
__libc_setup_tls ();
THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)[0]);
}
# define ARCH_SETUP_TLS() x86_setup_tls ()
# endif
#endif
#include <sysdeps/x86/cpu-features.c>

View File

@ -0,0 +1,37 @@
/* Linux/x86 CET initializers function.
Copyright (C) 2018 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
static inline int __attribute__ ((always_inline))
dl_cet_allocate_legacy_bitmap (unsigned long *legacy_bitmap)
{
/* FIXME: Need syscall support. */
return -1;
}
static inline int __attribute__ ((always_inline))
dl_cet_disable_cet (unsigned int cet_feature)
{
/* FIXME: Need syscall support. */
return -1;
}
static inline int __attribute__ ((always_inline))
dl_cet_lock_cet (void)
{
/* FIXME: Need syscall support. */
return -1;
}

View File

@ -13,3 +13,45 @@ ifeq ($(subdir),setjmp)
gen-as-const-headers += jmp_buf-ssp.sym
sysdep_routines += __longjmp_cancel
endif
ifeq ($(enable-cet),yes)
ifeq ($(subdir),elf)
sysdep-dl-routines += dl-cet
endif
# Add -fcf-protection to CFLAGS when CET is enabled.
CFLAGS-.o += -fcf-protection
CFLAGS-.os += -fcf-protection
CFLAGS-.op += -fcf-protection
CFLAGS-.oS += -fcf-protection
# Compile assembly codes with <cet.h> when CET is enabled.
asm-CPPFLAGS += -fcf-protection -include cet.h
ifeq ($(subdir),elf)
ifeq (yes,$(build-shared))
tests-special += $(objpfx)check-cet.out
endif
# FIXME: Can't use all-built-dso in elf/Makefile since this file is
# processed before elf/Makefile. Duplicate it here.
cet-built-dso := $(common-objpfx)elf/ld.so $(common-objpfx)libc.so \
$(filter-out $(common-objpfx)linkobj/libc.so, \
$(sort $(wildcard $(addprefix $(common-objpfx), \
*/lib*.so \
iconvdata/*.so))))
$(cet-built-dso:=.note): %.note: %
@rm -f $@T
LC_ALL=C $(READELF) -n $< > $@T
test -s $@T
mv -f $@T $@
common-generated += $(cet-built-dso:$(common-objpfx)%=%.note)
$(objpfx)check-cet.out: $(..)sysdeps/x86/check-cet.awk \
$(cet-built-dso:=.note)
LC_ALL=C $(AWK) -f $^ > $@; \
$(evaluate-test)
generated += check-cet.out
endif
endif

View File

@ -0,0 +1,29 @@
/* x86 CET tuning.
This file is part of the GNU C Library.
Copyright (C) 2018 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* Valid control values:
0: Enable CET features based on ELF property note.
1: Always disable CET features.
2: Always enable CET features.
3: Enable CET features permissively.
*/
#define CET_ELF_PROPERTY 0
#define CET_ALWAYS_OFF 1
#define CET_ALWAYS_ON 2
#define CET_PERMISSIVE 3
#define CET_MAX CET_PERMISSIVE

53
sysdeps/x86/check-cet.awk Normal file
View File

@ -0,0 +1,53 @@
# Verify that all shared objects contain the CET property.
# Copyright (C) 2018 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
#
# The GNU C Library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# The GNU C Library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with the GNU C Library; if not, see
# <http://www.gnu.org/licenses/>.
# This awk script expects to get command-line files that are each
# the output of 'readelf -n' on a single shared object.
# It exits successfully (0) if all of them contained the CET property.
# It fails (1) if any didn't contain the CET property
# It fails (2) if the input did not take the expected form.
BEGIN { result = cet = sanity = 0 }
function check_one(name) {
if (!sanity) {
print name ": *** input did not look like readelf -n output";
result = 2;
} else if (cet) {
print name ": OK";
} else {
print name ": *** no CET property found";
result = result ? result : 1;
}
cet = sanity = 0;
}
FILENAME != lastfile {
if (lastfile)
check_one(lastfile);
lastfile = FILENAME;
}
index ($0, "Displaying notes") != 0 { sanity = 1 }
index ($0, "IBT") != 0 && index ($0, "SHSTK") != 0 { cet = 1 }
END {
check_one(lastfile);
exit(result);
}

69
sysdeps/x86/configure vendored Normal file
View File

@ -0,0 +1,69 @@
# This file is generated from configure.ac by Autoconf. DO NOT EDIT!
# Local configure fragment for sysdeps/x86.
if test x"$enable_cet" = xyes; then
# Check if CET can be enabled.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CET can be enabled" >&5
$as_echo_n "checking whether CET can be enabled... " >&6; }
if ${libc_cv_x86_cet_available+:} false; then :
$as_echo_n "(cached) " >&6
else
cat > conftest.c <<EOF
#if !defined __CET__ || __CET__ != 3
# error CET isn't available.
#endif
EOF
if { ac_try='${CC-cc} -c $CFLAGS -fcf-protection -include cet.h conftest.c 1>&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
libc_cv_x86_cet_available=yes
else
libc_cv_x86_cet_available=no
fi
rm -rf conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_x86_cet_available" >&5
$as_echo "$libc_cv_x86_cet_available" >&6; }
if test $libc_cv_x86_cet_available = yes; then
enable_cet=yes
else
if test x"$enable_cet" = xdefault; then
enable_cet=no
else
as_fn_error $? "$CC doesn't support CET" "$LINENO" 5
fi
fi
fi
if test $enable_cet = yes; then
# Check if assembler supports CET.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $AS supports CET" >&5
$as_echo_n "checking whether $AS supports CET... " >&6; }
if ${libc_cv_x86_cet_as+:} false; then :
$as_echo_n "(cached) " >&6
else
cat > conftest.s <<EOF
incsspd %ecx
EOF
if { ac_try='${CC-cc} -c $CFLAGS conftest.s -o conftest.o 1>&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
libc_cv_x86_cet_as=yes
else
libc_cv_x86_cet_as=no
fi
rm -rf conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_x86_cet_as" >&5
$as_echo "$libc_cv_x86_cet_as" >&6; }
if test $libc_cv_x86_cet_as = no; then
as_fn_error $? "$AS doesn't support CET" "$LINENO" 5
fi
fi
config_vars="$config_vars
enable-cet = $enable_cet"

46
sysdeps/x86/configure.ac Normal file
View File

@ -0,0 +1,46 @@
GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
# Local configure fragment for sysdeps/x86.
if test x"$enable_cet" = xyes; then
# Check if CET can be enabled.
AC_CACHE_CHECK(whether CET can be enabled,
libc_cv_x86_cet_available, [dnl
cat > conftest.c <<EOF
#if !defined __CET__ || __CET__ != 3
# error CET isn't available.
#endif
EOF
if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS -fcf-protection -include cet.h conftest.c 1>&AS_MESSAGE_LOG_FD); then
libc_cv_x86_cet_available=yes
else
libc_cv_x86_cet_available=no
fi
rm -rf conftest*])
if test $libc_cv_x86_cet_available = yes; then
enable_cet=yes
else
if test x"$enable_cet" = xdefault; then
enable_cet=no
else
AC_MSG_ERROR([$CC doesn't support CET])
fi
fi
fi
if test $enable_cet = yes; then
# Check if assembler supports CET.
AC_CACHE_CHECK(whether $AS supports CET,
libc_cv_x86_cet_as, [dnl
cat > conftest.s <<EOF
incsspd %ecx
EOF
if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s -o conftest.o 1>&AS_MESSAGE_LOG_FD); then
libc_cv_x86_cet_as=yes
else
libc_cv_x86_cet_as=no
fi
rm -rf conftest*])
if test $libc_cv_x86_cet_as = no; then
AC_MSG_ERROR([$AS doesn't support CET])
fi
fi
LIBC_CONFIG_VAR([enable-cet], [$enable_cet])

View File

@ -28,6 +28,15 @@
extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *)
attribute_hidden;
# if CET_ENABLED
# include <dl-cet.h>
# include <cet-tunables.h>
extern void TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *)
attribute_hidden;
extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *)
attribute_hidden;
# endif
#endif
static void
@ -449,4 +458,55 @@ no_cpuid:
else if (CPU_FEATURES_ARCH_P (cpu_features, I586))
GLRO(dl_platform) = "i586";
#endif
#if CET_ENABLED
# if HAVE_TUNABLES
TUNABLE_GET (x86_ibt, tunable_val_t *,
TUNABLE_CALLBACK (set_x86_ibt));
TUNABLE_GET (x86_shstk, tunable_val_t *,
TUNABLE_CALLBACK (set_x86_shstk));
# endif
/* Check CET status. */
unsigned int cet_status = get_cet_status ();
if (cet_status)
{
GL(dl_x86_feature_1)[0] = cet_status;
# ifndef SHARED
/* Check if IBT and SHSTK are enabled by kernel. */
if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_IBT)
|| (cet_status & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
{
/* Disable IBT and/or SHSTK if they are enabled by kernel, but
disabled by environment variable:
GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
*/
unsigned int cet_feature = 0;
if (!HAS_CPU_FEATURE (IBT))
cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
if (!HAS_CPU_FEATURE (SHSTK))
cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
if (cet_feature)
{
int res = dl_cet_disable_cet (cet_feature);
/* Clear the disabled bits in dl_x86_feature_1. */
if (res == 0)
GL(dl_x86_feature_1)[0] &= ~cet_feature;
}
/* Lock CET if IBT or SHSTK is enabled in executable. Don't
lock CET if SHSTK is enabled permissively. */
if (((GL(dl_x86_feature_1)[1] >> CET_MAX)
& ((1 << CET_MAX) - 1))
!= CET_PERMISSIVE)
dl_cet_lock_cet ();
}
# endif
}
#endif
}

View File

@ -334,4 +334,52 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
}
while (*p != '\0');
}
# if CET_ENABLED
# include <cet-tunables.h>
attribute_hidden
void
TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *valp)
{
if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
{
GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1);
GL(dl_x86_feature_1)[1] |= CET_ALWAYS_ON;
}
else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
{
GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1);
GL(dl_x86_feature_1)[1] |= CET_ALWAYS_OFF;
}
else if (DEFAULT_MEMCMP (valp->strval, "permissive",
sizeof ("permissive")) == 0)
{
GL(dl_x86_feature_1)[1] &= ~((1 << CET_MAX) - 1);
GL(dl_x86_feature_1)[1] |= CET_PERMISSIVE;
}
}
attribute_hidden
void
TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *valp)
{
if (DEFAULT_MEMCMP (valp->strval, "on", sizeof ("on")) == 0)
{
GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX);
GL(dl_x86_feature_1)[1] |= (CET_ALWAYS_ON << CET_MAX);
}
else if (DEFAULT_MEMCMP (valp->strval, "off", sizeof ("off")) == 0)
{
GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX);
GL(dl_x86_feature_1)[1] |= (CET_ALWAYS_OFF << CET_MAX);
}
else if (DEFAULT_MEMCMP (valp->strval, "permissive",
sizeof ("permissive")) == 0)
{
GL(dl_x86_feature_1)[1] &= ~(((1 << CET_MAX) - 1) << CET_MAX);
GL(dl_x86_feature_1)[1] |= (CET_PERMISSIVE << CET_MAX);
}
}
# endif
#endif

346
sysdeps/x86/dl-cet.c Normal file
View File

@ -0,0 +1,346 @@
/* x86 CET initializers function.
Copyright (C) 2018 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <errno.h>
#include <libintl.h>
#include <ldsodefs.h>
#include <dl-cet.h>
#include <cet-tunables.h>
/* GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK
are defined in <elf.h>, which are only available for C sources.
X86_FEATURE_1_IBT and X86_FEATURE_1_SHSTK are defined in <sysdep.h>
which are available for both C and asm sources. They must match. */
#if GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
# error GNU_PROPERTY_X86_FEATURE_1_IBT != X86_FEATURE_1_IBT
#endif
#if GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
# error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK
#endif
static int
dl_cet_mark_legacy_region (struct link_map *l)
{
/* Mark PT_LOAD segments with PF_X in legacy code page bitmap. */
size_t i, phnum = l->l_phnum;
const ElfW(Phdr) *phdr = l->l_phdr;
#ifdef __x86_64__
typedef unsigned long long word_t;
#else
typedef unsigned long word_t;
#endif
unsigned int bits_to_set;
word_t mask_to_set;
#define BITS_PER_WORD (sizeof (word_t) * 8)
#define BITMAP_FIRST_WORD_MASK(start) \
(~((word_t) 0) << ((start) & (BITS_PER_WORD - 1)))
#define BITMAP_LAST_WORD_MASK(nbits) \
(~((word_t) 0) >> (-(nbits) & (BITS_PER_WORD - 1)))
word_t *bitmap = (word_t *) GL(dl_x86_legacy_bitmap)[0];
word_t bitmap_size = GL(dl_x86_legacy_bitmap)[1];
word_t *p;
size_t page_size = GLRO(dl_pagesize);
for (i = 0; i < phnum; i++)
if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X))
{
/* One bit in legacy bitmap represents a page. */
ElfW(Addr) start = (phdr[i].p_vaddr + l->l_addr) / page_size;
ElfW(Addr) len = (phdr[i].p_memsz + page_size - 1) / page_size;
ElfW(Addr) end = start + len;
if ((end / 8) > bitmap_size)
return -EINVAL;
p = bitmap + (start / BITS_PER_WORD);
bits_to_set = BITS_PER_WORD - (start % BITS_PER_WORD);
mask_to_set = BITMAP_FIRST_WORD_MASK (start);
while (len >= bits_to_set)
{
*p |= mask_to_set;
len -= bits_to_set;
bits_to_set = BITS_PER_WORD;
mask_to_set = ~((word_t) 0);
p++;
}
if (len)
{
mask_to_set &= BITMAP_LAST_WORD_MASK (end);
*p |= mask_to_set;
}
}
return 0;
}
/* Check if object M is compatible with CET. */
static void
dl_cet_check (struct link_map *m, const char *program)
{
/* Check how IBT should be enabled. */
unsigned int enable_ibt_type
= GL(dl_x86_feature_1)[1] & ((1 << CET_MAX) - 1);
/* Check how SHSTK should be enabled. */
unsigned int enable_shstk_type
= ((GL(dl_x86_feature_1)[1] >> CET_MAX) & ((1 << CET_MAX) - 1));
/* No legacy object check if both IBT and SHSTK are always on. */
if (enable_ibt_type == CET_ALWAYS_ON
&& enable_shstk_type == CET_ALWAYS_ON)
return;
/* Check if IBT is enabled by kernel. */
bool ibt_enabled
= (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0;
/* Check if SHSTK is enabled by kernel. */
bool shstk_enabled
= (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
if (ibt_enabled || shstk_enabled)
{
struct link_map *l = NULL;
/* Check if IBT and SHSTK are enabled in object. */
bool enable_ibt = (ibt_enabled
&& enable_ibt_type != CET_ALWAYS_OFF);
bool enable_shstk = (shstk_enabled
&& enable_shstk_type != CET_ALWAYS_OFF);
if (program)
{
/* Enable IBT and SHSTK only if they are enabled in executable.
NB: IBT and SHSTK may be disabled by environment variable:
GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
*/
enable_ibt &= (HAS_CPU_FEATURE (IBT)
&& (enable_ibt_type == CET_ALWAYS_ON
|| (m->l_cet & lc_ibt) != 0));
enable_shstk &= (HAS_CPU_FEATURE (SHSTK)
&& (enable_shstk_type == CET_ALWAYS_ON
|| (m->l_cet & lc_shstk) != 0));
}
/* ld.so is CET-enabled by kernel. But shared objects may not
support IBT nor SHSTK. */
if (enable_ibt || enable_shstk)
{
int res;
unsigned int i;
unsigned int first_legacy, last_legacy;
bool need_legacy_bitmap = false;
i = m->l_searchlist.r_nlist;
while (i-- > 0)
{
/* Check each shared object to see if IBT and SHSTK are
enabled. */
l = m->l_initfini[i];
if (l->l_init_called)
continue;
#ifdef SHARED
/* Skip CET check for ld.so since ld.so is CET-enabled.
CET will be disabled later if CET isn't enabled in
executable. */
if (l == &GL(dl_rtld_map)
|| l->l_real == &GL(dl_rtld_map)
|| (program && l == m))
continue;
#endif
if (enable_ibt
&& enable_ibt_type != CET_ALWAYS_ON
&& !(l->l_cet & lc_ibt))
{
/* Remember the first and last legacy objects. */
if (!need_legacy_bitmap)
last_legacy = i;
first_legacy = i;
need_legacy_bitmap = true;
}
/* SHSTK is enabled only if it is enabled in executable as
well as all shared objects. */
enable_shstk &= (enable_shstk_type == CET_ALWAYS_ON
|| (l->l_cet & lc_shstk) != 0);
}
if (need_legacy_bitmap)
{
if (GL(dl_x86_legacy_bitmap)[0])
{
/* Change legacy bitmap to writable. */
if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0],
GL(dl_x86_legacy_bitmap)[1],
PROT_READ | PROT_WRITE) < 0)
{
mprotect_failure:
if (program)
_dl_fatal_printf ("%s: mprotect legacy bitmap failed\n",
l->l_name);
else
_dl_signal_error (EINVAL, l->l_name, "dlopen",
N_("mprotect legacy bitmap failed"));
}
}
else
{
/* Allocate legacy bitmap. */
int res = dl_cet_allocate_legacy_bitmap
(GL(dl_x86_legacy_bitmap));
if (res != 0)
{
if (program)
_dl_fatal_printf ("%s: legacy bitmap isn't available\n",
l->l_name);
else
_dl_signal_error (EINVAL, l->l_name, "dlopen",
N_("legacy bitmap isn't available"));
}
}
/* Put legacy shared objects in legacy bitmap. */
for (i = first_legacy; i <= last_legacy; i++)
{
l = m->l_initfini[i];
if (l->l_init_called || (l->l_cet & lc_ibt))
continue;
#ifdef SHARED
if (l == &GL(dl_rtld_map)
|| l->l_real == &GL(dl_rtld_map)
|| (program && l == m))
continue;
#endif
/* If IBT is enabled in executable and IBT isn't enabled
in this shard object, mark PT_LOAD segments with PF_X
in legacy code page bitmap. */
res = dl_cet_mark_legacy_region (l);
if (res != 0)
{
if (program)
_dl_fatal_printf ("%s: failed to mark legacy code region\n",
l->l_name);
else
_dl_signal_error (-res, l->l_name, "dlopen",
N_("failed to mark legacy code region"));
}
}
/* Change legacy bitmap to read-only. */
if (__mprotect ((void *) GL(dl_x86_legacy_bitmap)[0],
GL(dl_x86_legacy_bitmap)[1], PROT_READ) < 0)
goto mprotect_failure;
}
}
bool cet_feature_changed = false;
if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled)
{
if (!program
&& enable_shstk_type != CET_PERMISSIVE)
{
/* When SHSTK is enabled, we can't dlopening a shared
object without SHSTK. */
if (enable_shstk != shstk_enabled)
_dl_signal_error (EINVAL, l->l_name, "dlopen",
N_("shadow stack isn't enabled"));
return;
}
/* Disable IBT and/or SHSTK if they are enabled by kernel, but
disabled in executable or shared objects. */
unsigned int cet_feature = 0;
/* Disable IBT only during program startup. */
if (program && !enable_ibt)
cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
if (!enable_shstk)
cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
int res = dl_cet_disable_cet (cet_feature);
if (res != 0)
{
if (program)
_dl_fatal_printf ("%s: can't disable CET\n", program);
else
_dl_signal_error (-res, l->l_name, "dlopen",
N_("can't disable CET"));
}
/* Clear the disabled bits in dl_x86_feature_1. */
GL(dl_x86_feature_1)[0] &= ~cet_feature;
cet_feature_changed = true;
}
#ifdef SHARED
if (program
&& (!shstk_enabled
|| enable_shstk_type != CET_PERMISSIVE)
&& (ibt_enabled || shstk_enabled))
{
/* Lock CET if IBT or SHSTK is enabled in executable. Don't
lock CET if SHSTK is enabled permissively. */
int res = dl_cet_lock_cet ();
if (res != 0)
_dl_fatal_printf ("%s: can't lock CET\n", program);
cet_feature_changed = true;
}
#endif
if (cet_feature_changed)
{
unsigned int feature_1 = 0;
if (enable_ibt)
feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT;
if (enable_shstk)
feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
struct pthread *self = THREAD_SELF;
THREAD_SETMEM (self, header.feature_1, feature_1);
}
}
}
void
_dl_cet_open_check (struct link_map *l)
{
dl_cet_check (l, NULL);
}
#ifdef SHARED
# ifndef LINKAGE
# define LINKAGE
# endif
LINKAGE
void
_dl_cet_check (struct link_map *main_map, const char *program)
{
dl_cet_check (main_map, program);
}
#endif /* SHARED */

View File

@ -0,0 +1,68 @@
/* Data for processor runtime information. x86 version.
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* This information must be kept in sync with the _DL_HWCAP_COUNT,
HWCAP_PLATFORMS_START and HWCAP_PLATFORMS_COUNT definitions in
dl-hwcap.h.
If anything should be added here check whether the size of each string
is still ok with the given array size.
All the #ifdefs in the definitions are quite irritating but
necessary if we want to avoid duplicating the information. There
are three different modes:
- PROCINFO_DECL is defined. This means we are only interested in
declarations.
- PROCINFO_DECL is not defined:
+ if SHARED is defined the file is included in an array
initializer. The .element = { ... } syntax is needed.
+ if SHARED is not defined a normal array initialization is
needed.
*/
#ifndef PROCINFO_CLASS
# define PROCINFO_CLASS
#endif
#if !IS_IN (ldconfig)
# if !defined PROCINFO_DECL && defined SHARED
._dl_x86_feature_1
# else
PROCINFO_CLASS unsigned int _dl_x86_feature_1[2]
# endif
# if !defined SHARED || defined PROCINFO_DECL
;
# else
,
# endif
# if !defined PROCINFO_DECL && defined SHARED
._dl_x86_legacy_bitmap
# else
PROCINFO_CLASS unsigned long _dl_x86_legacy_bitmap[2]
# endif
# if !defined SHARED || defined PROCINFO_DECL
;
# else
,
# endif
#endif

153
sysdeps/x86/dl-prop.h Normal file
View File

@ -0,0 +1,153 @@
/* Support for GNU properties. x86 version.
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef _DL_PROP_H
#define _DL_PROP_H
#include <not-cancel.h>
extern void _dl_cet_check (struct link_map *, const char *)
attribute_hidden;
extern void _dl_cet_open_check (struct link_map *)
attribute_hidden;
static inline void __attribute__ ((always_inline))
_rtld_main_check (struct link_map *m, const char *program)
{
#if CET_ENABLED
_dl_cet_check (m, program);
#endif
}
static inline void __attribute__ ((always_inline))
_dl_open_check (struct link_map *m)
{
#if CET_ENABLED
_dl_cet_open_check (m);
#endif
}
static inline void __attribute__ ((unused))
_dl_process_cet_property_note (struct link_map *l,
const ElfW(Nhdr) *note,
const ElfW(Addr) size,
const ElfW(Addr) align)
{
#if CET_ENABLED
/* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
32-bit objects and to 8 bytes in 64-bit objects. Skip notes
with incorrect alignment. */
if (align != (__ELF_NATIVE_CLASS / 8))
return;
const ElfW(Addr) start = (ElfW(Addr)) note;
while ((ElfW(Addr)) (note + 1) - start < size)
{
/* Find the NT_GNU_PROPERTY_TYPE_0 note. */
if (note->n_namesz == 4
&& note->n_type == NT_GNU_PROPERTY_TYPE_0
&& memcmp (note + 1, "GNU", 4) == 0)
{
/* Check for invalid property. */
if (note->n_descsz < 8
|| (note->n_descsz % sizeof (ElfW(Addr))) != 0)
break;
/* Start and end of property array. */
unsigned char *ptr = (unsigned char *) (note + 1) + 4;
unsigned char *ptr_end = ptr + note->n_descsz;
while (1)
{
unsigned int type = *(unsigned int *) ptr;
unsigned int datasz = *(unsigned int *) (ptr + 4);
ptr += 8;
if ((ptr + datasz) > ptr_end)
break;
if (type == GNU_PROPERTY_X86_FEATURE_1_AND
&& datasz == 4)
{
unsigned int feature_1 = *(unsigned int *) ptr;
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
l->l_cet |= lc_ibt;
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
l->l_cet |= lc_shstk;
break;
}
}
}
/* NB: Note sections like .note.ABI-tag and .note.gnu.build-id are
aligned to 4 bytes in 64-bit ELF objects. */
note = ((const void *) note
+ ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
align));
}
#endif
}
#ifdef FILEBUF_SIZE
static inline int __attribute__ ((unused))
_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph,
int fd, struct filebuf *fbp)
{
# if CET_ENABLED
const ElfW(Nhdr) *note;
ElfW(Nhdr) *note_malloced = NULL;
ElfW(Addr) size = ph->p_filesz;
if (ph->p_offset + size <= (size_t) fbp->len)
note = (const void *) (fbp->buf + ph->p_offset);
else
{
if (size < __MAX_ALLOCA_CUTOFF)
note = alloca (size);
else
{
note_malloced = malloc (size);
note = note_malloced;
}
__lseek (fd, ph->p_offset, SEEK_SET);
if (__read_nocancel (fd, (void *) note, size) != size)
{
if (note_malloced)
free (note_malloced);
return -1;
}
}
_dl_process_cet_property_note (l, note, size, ph->p_align);
if (note_malloced)
free (note_malloced);
# endif
return 0;
}
#endif
static inline int __attribute__ ((unused))
_rtld_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph)
{
const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
_dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align);
return 0;
}
#endif /* _DL_PROP_H */

View File

@ -21,6 +21,12 @@ glibc {
hwcaps {
type: STRING
}
x86_ibt {
type: STRING
}
x86_shstk {
type: STRING
}
x86_non_temporal_threshold {
type: SIZE_T
}

25
sysdeps/x86/libc-start.h Normal file
View File

@ -0,0 +1,25 @@
/* X86 definitions for libc main startup.
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef SHARED
# define ARCH_SETUP_IREL() apply_irel ()
# define ARCH_APPLY_IREL()
# ifndef ARCH_SETUP_TLS
# define ARCH_SETUP_TLS() __libc_setup_tls ()
# endif
#endif /* !SHARED */

26
sysdeps/x86/link_map.h Normal file
View File

@ -0,0 +1,26 @@
/* Additional fields in struct link_map. Linux/x86 version.
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* If this object is enabled with CET. */
enum
{
lc_none = 0, /* Not enabled with CET. */
lc_ibt = 1 << 0, /* Enabled with IBT. */
lc_shstk = 1 << 1, /* Enabled with STSHK. */
lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */
} l_cet:2;

View File

@ -52,6 +52,13 @@ enum cf_protection_level
/* Syntactic details of assembler. */
#ifdef _CET_ENDBR
# define _CET_NOTRACK notrack
#else
# define _CET_ENDBR
# define _CET_NOTRACK
#endif
/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */
#define ALIGNARG(log2) 1<<log2
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
@ -63,6 +70,7 @@ enum cf_protection_level
.align ALIGNARG(4); \
C_LABEL(name) \
cfi_startproc; \
_CET_ENDBR; \
CALL_MCOUNT
#undef END

View File

@ -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