diff --git a/SOURCES/glibc-rh1855790-1.patch b/SOURCES/glibc-rh1855790-1.patch new file mode 100644 index 0000000..91eaf37 --- /dev/null +++ b/SOURCES/glibc-rh1855790-1.patch @@ -0,0 +1,120 @@ +commit 15eab1e3e89129ab3ed03f5bdc3415b26e9caeb9 +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386: Don't unnecessarily save and restore EAX, ECX and EDX [BZ# 25262] + + On i386, since EAX, ECX and EDX are caller-saved, there are no need + to save and restore EAX, ECX and EDX in getcontext, setcontext and + swapcontext. They just need to clear EAX on success. The extra + scratch registers are needed to enable CET. + + Tested on i386. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/getcontext.S b/sysdeps/unix/sysv/linux/i386/getcontext.S +index 26ca08a..6637596 100644 +--- a/sysdeps/unix/sysv/linux/i386/getcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/getcontext.S +@@ -26,13 +26,7 @@ ENTRY(__getcontext) + /* Load address of the context data structure. */ + movl 4(%esp), %eax + +- /* Return value of getcontext. EAX is the only register whose +- value is not preserved. */ +- movl $0, oEAX(%eax) +- +- /* Save the 32-bit register values and the return address. */ +- movl %ecx, oECX(%eax) +- movl %edx, oEDX(%eax) ++ /* Save the preserved register values and the return address. */ + movl %edi, oEDI(%eax) + movl %esi, oESI(%eax) + movl %ebp, oEBP(%eax) +diff --git a/sysdeps/unix/sysv/linux/i386/setcontext.S b/sysdeps/unix/sysv/linux/i386/setcontext.S +index a604fca..7565d7d 100644 +--- a/sysdeps/unix/sysv/linux/i386/setcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/setcontext.S +@@ -65,22 +65,19 @@ ENTRY(__setcontext) + cfi_offset (esi, oESI) + cfi_offset (ebp, oEBP) + cfi_offset (ebx, oEBX) +- cfi_offset (edx, oEDX) +- cfi_offset (ecx, oECX) + movl oESP(%eax), %esp + + /* Push the return address on the new stack so we can return there. */ + pushl %ecx + +- /* Load the values of all the 32-bit registers (except ESP). +- Since we are loading from EAX, it must be last. */ ++ /* Load the values of all the preserved registers (except ESP). */ + movl oEDI(%eax), %edi + movl oESI(%eax), %esi + movl oEBP(%eax), %ebp + movl oEBX(%eax), %ebx +- movl oEDX(%eax), %edx +- movl oECX(%eax), %ecx +- movl oEAX(%eax), %eax ++ ++ /* All done, return 0 for success. */ ++ xorl %eax, %eax + + /* End FDE here, we fall into another context. */ + cfi_endproc +diff --git a/sysdeps/unix/sysv/linux/i386/swapcontext.S b/sysdeps/unix/sysv/linux/i386/swapcontext.S +index 431f22c..ce27d51 100644 +--- a/sysdeps/unix/sysv/linux/i386/swapcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/swapcontext.S +@@ -26,13 +26,7 @@ ENTRY(__swapcontext) + /* Load address of the context data structure we save in. */ + movl 4(%esp), %eax + +- /* Return value of swapcontext. EAX is the only register whose +- value is not preserved. */ +- movl $0, oEAX(%eax) +- +- /* Save the 32-bit register values and the return address. */ +- movl %ecx, oECX(%eax) +- movl %edx, oEDX(%eax) ++ /* Save the preserved register values and the return address. */ + movl %edi, oEDI(%eax) + movl %esi, oESI(%eax) + movl %ebp, oEBP(%eax) +@@ -91,15 +85,14 @@ ENTRY(__swapcontext) + /* Push the return address on the new stack so we can return there. */ + pushl %ecx + +- /* Load the values of all the 32-bit registers (except ESP). +- Since we are loading from EAX, it must be last. */ ++ /* Load the values of all the preserved registers (except ESP). */ + movl oEDI(%eax), %edi + movl oESI(%eax), %esi + movl oEBP(%eax), %ebp + movl oEBX(%eax), %ebx +- movl oEDX(%eax), %edx +- movl oECX(%eax), %ecx +- movl oEAX(%eax), %eax ++ ++ /* All done, return 0 for success. */ ++ xorl %eax, %eax + + /* The following 'ret' will pop the address of the code and jump + to it. */ +diff --git a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +index b11a550..1dfe03d 100644 +--- a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym ++++ b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +@@ -21,9 +21,6 @@ oESI mreg (ESI) + oEBP mreg (EBP) + oESP mreg (ESP) + oEBX mreg (EBX) +-oEDX mreg (EDX) +-oECX mreg (ECX) +-oEAX mreg (EAX) + oEIP mreg (EIP) + oFPREGS mcontext (fpregs) + oSIGMASK ucontext (uc_sigmask) + diff --git a/SOURCES/glibc-rh1855790-10.patch b/SOURCES/glibc-rh1855790-10.patch new file mode 100644 index 0000000..fb4a056 --- /dev/null +++ b/SOURCES/glibc-rh1855790-10.patch @@ -0,0 +1,380 @@ +commit 9e38f455a6c602be86b7b5a8d6523cbdcd7ec051 +Author: H.J. Lu +Date: Mon Apr 27 15:44:07 2020 -0700 + + x86: Add --enable-cet=permissive + + When CET is enabled, it is an error to dlopen a non CET enabled shared + library in CET enabled application. It may be desirable to make CET + permissive, that is disable CET when dlopening a non CET enabled shared + library. With the new --enable-cet=permissive configure option, CET is + disabled when dlopening a non CET enabled shared library. + + Add DEFAULT_DL_X86_CET_CONTROL to config.h.in: + + /* The default value of x86 CET control. */ + #define DEFAULT_DL_X86_CET_CONTROL cet_elf_property + + which enables CET features based on ELF property note. + + --enable-cet=permissive it to + + /* The default value of x86 CET control. */ + #define DEFAULT_DL_X86_CET_CONTROL cet_permissive + + which enables CET features permissively. + + Update tst-cet-legacy-5a, tst-cet-legacy-5b, tst-cet-legacy-6a and + tst-cet-legacy-6b to check --enable-cet and --enable-cet=permissive. +--- + +diff --git a/INSTALL b/INSTALL +index d56e102..0655650 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -116,20 +116,24 @@ if 'CFLAGS' is specified it must enable optimization. For example: + executables (PIE) by default. + + '--enable-cet' ++'--enable-cet=permissive' + Enable Intel Control-flow Enforcement Technology (CET) support. +- When the GNU C Library is built with '--enable-cet', the resulting +- library is protected with indirect branch tracking (IBT) and shadow +- stack (SHSTK). When CET is enabled, the GNU C Library is +- compatible with all existing executables and shared libraries. +- This feature is currently supported on i386, x86_64 and x32 with +- GCC 8 and binutils 2.29 or later. Note that when CET is enabled, +- the GNU C Library requires CPUs capable of multi-byte NOPs, like +- x86-64 processors as well as Intel Pentium Pro or newer. ++ When the GNU C Library is built with '--enable-cet' or ++ '--enable-cet=permissive', the resulting library is protected with ++ indirect branch tracking (IBT) and shadow stack (SHSTK). When CET ++ is enabled, the GNU C Library is compatible with all existing ++ executables and shared libraries. This feature is currently ++ supported on i386, x86_64 and x32 with GCC 8 and binutils 2.29 or ++ later. Note that when CET is enabled, the GNU C Library requires ++ CPUs capable of multi-byte NOPs, like x86-64 processors as well as ++ Intel Pentium Pro or newer. With '--enable-cet', it is an error to ++ dlopen a non CET enabled shared library in CET enabled application. ++ With '--enable-cet=permissive', CET is disabled when dlopening a ++ non CET enabled shared library in CET enabled application. + + NOTE: '--enable-cet' has been tested for i686, x86_64 and x32 on +- non-CET processors. '--enable-cet' has been tested for x86_64 and +- x32 on CET SDVs, but Intel CET support hasn't been validated for +- i686. ++ non-CET processors. '--enable-cet' has been tested for i686, ++ x86_64 and x32 on CET processors. + + '--disable-profile' + Don't build libraries with profiling information. You may want to +diff --git a/config.h.in b/config.h.in +index f63f6c8..8520b0f 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -259,4 +259,7 @@ + in i386 6 argument syscall issue). */ + #define CAN_USE_REGISTER_ASM_EBP 0 + ++/* The default value of x86 CET control. */ ++#define DEFAULT_DL_X86_CET_CONTROL cet_elf_property ++ + #endif +diff --git a/manual/install.texi b/manual/install.texi +index 351d67c..7e9f2be 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -147,20 +147,24 @@ PIE. This option also implies that glibc programs and tests are created + as dynamic position independent executables (PIE) by default. + + @item --enable-cet ++@itemx --enable-cet=permissive + Enable Intel Control-flow Enforcement Technology (CET) support. When +-@theglibc{} is built with @option{--enable-cet}, the resulting library ++@theglibc{} is built with @option{--enable-cet} or ++@option{--enable-cet=permissive}, the resulting library + is protected with indirect branch tracking (IBT) and shadow stack + (SHSTK)@. When CET is enabled, @theglibc{} is compatible with all + existing executables and shared libraries. This feature is currently + supported on i386, x86_64 and x32 with GCC 8 and binutils 2.29 or later. + Note that when CET is enabled, @theglibc{} requires CPUs capable of + multi-byte NOPs, like x86-64 processors as well as Intel Pentium Pro or +-newer. ++newer. With @option{--enable-cet}, it is an error to dlopen a non CET ++enabled shared library in CET enabled application. With ++@option{--enable-cet=permissive}, CET is disabled when dlopening a ++non CET enabled shared library in CET enabled application. + + NOTE: @option{--enable-cet} has been tested for i686, x86_64 and x32 + on non-CET processors. @option{--enable-cet} has been tested for +-x86_64 and x32 on CET SDVs, but Intel CET support hasn't been validated +-for i686. ++i686, x86_64 and x32 on CET processors. + + @item --disable-profile + Don't build libraries with profiling information. You may want to use +diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile +index 7dc4e61..8ac2fd4 100644 +--- a/sysdeps/unix/sysv/linux/x86/Makefile ++++ b/sysdeps/unix/sysv/linux/x86/Makefile +@@ -24,7 +24,7 @@ ifeq ($(subdir),setjmp) + tests += tst-saved_mask-1 + endif + +-ifeq ($(enable-cet),yes) ++ifneq ($(enable-cet),no) + ifeq ($(subdir),elf) + tests += tst-cet-property-1 tst-cet-property-2 + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index d9bdf0b..d5f821e 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -14,7 +14,7 @@ gen-as-const-headers += jmp_buf-ssp.sym + sysdep_routines += __longjmp_cancel + endif + +-ifeq ($(enable-cet),yes) ++ifneq ($(enable-cet),no) + ifeq ($(subdir),elf) + sysdep-dl-routines += dl-cet + +@@ -41,13 +41,21 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-4a.c += -fcf-protection + CFLAGS-tst-cet-legacy-4b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none +-CFLAGS-tst-cet-legacy-5a.c += -fcf-protection +-CFLAGS-tst-cet-legacy-5b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-5a.c += -fcf-protection -mshstk ++ifeq ($(enable-cet),permissive) ++CPPFLAGS-tst-cet-legacy-5a.c += -DCET_IS_PERMISSIVE=1 ++endif ++CFLAGS-tst-cet-legacy-5b.c += -fcf-protection -mshstk ++CPPFLAGS-tst-cet-legacy-5b.c += -DCET_DISABLED_BY_ENV=1 + CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection +-CFLAGS-tst-cet-legacy-6a.c += -fcf-protection +-CFLAGS-tst-cet-legacy-6b.c += -fcf-protection ++CFLAGS-tst-cet-legacy-6a.c += -fcf-protection -mshstk ++ifeq ($(enable-cet),permissive) ++CPPFLAGS-tst-cet-legacy-6a.c += -DCET_IS_PERMISSIVE=1 ++endif ++CFLAGS-tst-cet-legacy-6b.c += -fcf-protection -mshstk ++CPPFLAGS-tst-cet-legacy-6b.c += -DCET_DISABLED_BY_ENV=1 + CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection +diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure +index b1ff281..81cc4e8 100644 +--- a/sysdeps/x86/configure ++++ b/sysdeps/x86/configure +@@ -1,7 +1,7 @@ + # 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 ++if test $enable_cet != no; 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; } +@@ -27,17 +27,11 @@ EOF + 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 ++ if test $libc_cv_x86_cet_available != yes; then ++ as_fn_error $? "$CC doesn't support CET" "$LINENO" 5 + fi + fi +-if test $enable_cet = yes; then ++if test $enable_cet != no; 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; } +@@ -65,5 +59,12 @@ $as_echo "$libc_cv_x86_cet_as" >&6; } + as_fn_error $? "$AS doesn't support CET" "$LINENO" 5 + fi + fi ++if test $enable_cet = yes; then ++ $as_echo "#define DEFAULT_DL_X86_CET_CONTROL cet_elf_property" >>confdefs.h ++ ++elif test $enable_cet = permissive; then ++ $as_echo "#define DEFAULT_DL_X86_CET_CONTROL cet_permissive" >>confdefs.h ++ ++fi + config_vars="$config_vars + enable-cet = $enable_cet" +diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac +index a909b07..8f3e119 100644 +--- a/sysdeps/x86/configure.ac ++++ b/sysdeps/x86/configure.ac +@@ -1,7 +1,7 @@ + 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 ++if test $enable_cet != no; then + # Check if CET can be enabled. + AC_CACHE_CHECK(whether CET can be enabled, + libc_cv_x86_cet_available, [dnl +@@ -16,17 +16,11 @@ EOF + 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 ++ if test $libc_cv_x86_cet_available != yes; then ++ AC_MSG_ERROR([$CC doesn't support CET]) + fi + fi +-if test $enable_cet = yes; then ++if test $enable_cet != no; then + # Check if assembler supports CET. + AC_CACHE_CHECK(whether $AS supports CET, + libc_cv_x86_cet_as, [dnl +@@ -43,4 +37,9 @@ EOF + AC_MSG_ERROR([$AS doesn't support CET]) + fi + fi ++if test $enable_cet = yes; then ++ AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_elf_property) ++elif test $enable_cet = permissive; then ++ AC_DEFINE(DEFAULT_DL_X86_CET_CONTROL, cet_permissive) ++fi + LIBC_CONFIG_VAR([enable-cet], [$enable_cet]) +diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c +index 26b2b39..72b16fa 100644 +--- a/sysdeps/x86/dl-procruntime.c ++++ b/sysdeps/x86/dl-procruntime.c +@@ -65,8 +65,8 @@ PROCINFO_CLASS struct dl_x86_feature_control _dl_x86_feature_control + # endif + # ifndef PROCINFO_DECL + = { +- .ibt = cet_elf_property, +- .shstk = cet_elf_property ++ .ibt = DEFAULT_DL_X86_CET_CONTROL, ++ .shstk = DEFAULT_DL_X86_CET_CONTROL, + } + # endif + # if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +index 0a34d37..c578979 100644 +--- a/sysdeps/x86/tst-cet-legacy-5.c ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -22,6 +22,14 @@ + #include + #include + #include ++#include ++#include ++ ++#if defined CET_IS_PERMISSIVE || defined CET_DISABLED_BY_ENV ++# define CET_MAYBE_DISABLED 1 ++#else ++# define CET_MAYBE_DISABLED 0 ++#endif + + static void + do_test_1 (const char *modname, bool fail) +@@ -32,24 +40,25 @@ do_test_1 (const char *modname, bool fail) + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { ++ const char *err = dlerror (); + if (fail) + { +- const char *err = dlerror (); + if (strstr (err, "rebuild shared object with SHSTK support enabled") + == NULL) +- { +- printf ("incorrect dlopen '%s' error: %s\n", modname, +- err); +- exit (1); +- } ++ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); + + return; + } + +- printf ("cannot open '%s': %s\n", modname, dlerror ()); +- exit (1); ++ FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err); + } + ++ /* NB: dlopen should never fail on non-CET platforms. If SHSTK is ++ disabled, assuming IBT is also disabled. */ ++ bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED; ++ if (fail && cet_enabled) ++ FAIL_EXIT1 ("dlopen should have failed\n"); ++ + fp = dlsym (h, "test"); + if (fp == NULL) + { +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +index bd45218..78e72ba 100644 +--- a/sysdeps/x86/tst-cet-legacy-6.c ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -22,6 +22,14 @@ + #include + #include + #include ++#include ++#include ++ ++#if defined CET_IS_PERMISSIVE || defined CET_DISABLED_BY_ENV ++# define CET_MAYBE_DISABLED 1 ++#else ++# define CET_MAYBE_DISABLED 0 ++#endif + + static void + do_test_1 (const char *modname, bool fail) +@@ -32,24 +40,25 @@ do_test_1 (const char *modname, bool fail) + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { ++ const char *err = dlerror (); + if (fail) + { +- const char *err = dlerror (); + if (strstr (err, "rebuild shared object with SHSTK support enabled") + == NULL) +- { +- printf ("incorrect dlopen '%s' error: %s\n", modname, +- err); +- exit (1); +- } ++ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); + + return; + } + +- printf ("cannot open '%s': %s\n", modname, dlerror ()); +- exit (1); ++ FAIL_EXIT1 ("cannot open '%s': %s\n", modname, err); + } + ++ /* NB: dlopen should never fail on non-CET platforms. If SHSTK is ++ disabled, assuming IBT is also disabled. */ ++ bool cet_enabled = _get_ssp () != 0 && !CET_MAYBE_DISABLED; ++ if (fail && cet_enabled) ++ FAIL_EXIT1 ("dlopen should have failed\n"); ++ + fp = dlsym (h, "test"); + if (fp == NULL) + { + diff --git a/SOURCES/glibc-rh1855790-11.patch b/SOURCES/glibc-rh1855790-11.patch new file mode 100644 index 0000000..8f6d3c4 --- /dev/null +++ b/SOURCES/glibc-rh1855790-11.patch @@ -0,0 +1,293 @@ +commit c02695d776406faaf63418e4e80c4a7023af0b4f +Author: H.J. Lu +Date: Wed Sep 16 16:00:14 2020 -0700 + + x86/CET: Update vfork to prevent child return + + Child of vfork should either call _exit or one of the exec family of + functions. But normally there is nothing to prevent child of vfork from + return of the vfork-calling function. Simpilfy x86 vfork when shadow + stack is in use to introduce mismatched shadow stack in child of vfork + to trigger SIGSEGV when the child returns from the function in which + vfork was called. +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S +index ceb41db0bd..91277a639f 100644 +--- a/sysdeps/unix/sysv/linux/i386/vfork.S ++++ b/sysdeps/unix/sysv/linux/i386/vfork.S +@@ -21,39 +21,6 @@ + #include + #include + +-#if SHSTK_ENABLED +-/* The shadow stack prevents us from pushing the saved return PC onto +- the stack and returning normally. Instead we pop the shadow stack +- and return directly. This is the safest way to return and ensures +- any stack manipulations done by the vfork'd child doesn't cause the +- parent to terminate when CET is enabled. */ +-# undef SYSCALL_ERROR_HANDLER +-# ifdef PIC +-# define SYSCALL_ERROR_HANDLER \ +-0: \ +- calll .L1; \ +-.L1: \ +- popl %edx; \ +-.L2: \ +- addl $_GLOBAL_OFFSET_TABLE_ + (.L2 - .L1), %edx; \ +- movl __libc_errno@gotntpoff(%edx), %edx; \ +- negl %eax; \ +- movl %eax, %gs:(%edx); \ +- orl $-1, %eax; \ +- jmp 1b; +-# else +-# define SYSCALL_ERROR_HANDLER \ +-0: \ +- movl __libc_errno@indntpoff, %edx; \ +- negl %eax; \ +- movl %eax, %gs:(%edx); \ +- orl $-1, %eax; \ +- jmp 1b; +-# endif +-# undef SYSCALL_ERROR_LABEL +-# define SYSCALL_ERROR_LABEL 0f +-#endif +- + /* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, +@@ -70,20 +37,17 @@ ENTRY (__vfork) + movl $SYS_ify (vfork), %eax + int $0x80 + +-#if !SHSTK_ENABLED + /* Jump to the return PC. Don't jump directly since this + disturbs the branch target cache. Instead push the return + address back on the stack. */ + pushl %ecx + cfi_adjust_cfa_offset (4) +-#endif + + cmpl $-4095, %eax + /* Branch forward if it failed. */ + jae SYSCALL_ERROR_LABEL + + #if SHSTK_ENABLED +-1: + /* Check if shadow stack is in use. */ + xorl %edx, %edx + rdsspd %edx +@@ -91,18 +55,19 @@ ENTRY (__vfork) + /* Normal return if shadow stack isn't in use. */ + je L(no_shstk) + +- /* Pop return address from shadow stack and jump back to caller +- directly. */ +- movl $1, %edx +- incsspd %edx ++ testl %eax, %eax ++ /* In parent, normal return. */ ++ jnz L(no_shstk) ++ ++ /* NB: In child, jump back to caller via indirect branch without ++ popping shadow stack which is shared with parent. Keep shadow ++ stack mismatched so that child returns in the vfork-calling ++ function will trigger SIGSEGV. */ ++ popl %ecx ++ cfi_adjust_cfa_offset (-4) + jmp *%ecx + + L(no_shstk): +- /* Jump to the return PC. Don't jump directly since this +- disturbs the branch target cache. Instead push the return +- address back on the stack. */ +- pushl %ecx +- cfi_adjust_cfa_offset (4) + #endif + + ret +diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile +index 50fd018fa3..6bfd6bec49 100644 +--- a/sysdeps/unix/sysv/linux/x86/Makefile ++++ b/sysdeps/unix/sysv/linux/x86/Makefile +@@ -40,6 +40,11 @@ $(objpfx)tst-cet-property-2.out: $(objpfx)tst-cet-property-2 \ + $(evaluate-test) + endif + ++ifeq ($(subdir),posix) ++tests += tst-cet-vfork-1 ++CFLAGS-tst-cet-vfork-1.c += -mshstk ++endif ++ + ifeq ($(subdir),stdlib) + tests += tst-cet-setcontext-1 + CFLAGS-tst-cet-setcontext-1.c += -mshstk +diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c b/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c +new file mode 100644 +index 0000000000..5b9fc8c170 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c +@@ -0,0 +1,88 @@ ++/* Verify that child of the vfork-calling function can't return when ++ shadow stack is in use. ++ Copyright (C) 2020 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++__attribute__ ((noclone, noinline)) ++static void ++do_test_1 (void) ++{ ++ pid_t p1; ++ int fd[2]; ++ ++ if (pipe (fd) == -1) ++ { ++ puts ("pipe failed"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ if ((p1 = vfork ()) == 0) ++ { ++ pid_t p = getpid (); ++ TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))); ++ /* Child return should trigger SIGSEGV. */ ++ return; ++ } ++ else if (p1 == -1) ++ { ++ puts ("vfork failed"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ pid_t p2 = 0; ++ if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) ++ != sizeof (pid_t)) ++ puts ("pipd read failed"); ++ else ++ { ++ int r; ++ if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) ++ puts ("waitpid failed"); ++ else if (r != 0) ++ puts ("pip write in child failed"); ++ } ++ ++ /* Parent exits immediately so that parent returns without triggering ++ SIGSEGV when shadow stack isn't in use. */ ++ _exit (EXIT_FAILURE); ++} ++ ++static int ++do_test (void) ++{ ++ /* NB: This test should trigger SIGSEGV with shadow stack enabled. */ ++ if (_get_ssp () == 0) ++ return EXIT_UNSUPPORTED; ++ do_test_1 (); ++ /* Child exits immediately so that child returns without triggering ++ SIGSEGV when shadow stack isn't in use. */ ++ _exit (EXIT_FAILURE); ++} ++ ++#define EXPECTED_SIGNAL (_get_ssp () == 0 ? 0 : SIGSEGV) ++#include +diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S +index 776d2fc610..613ff7e846 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/vfork.S ++++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S +@@ -20,22 +20,6 @@ + #include + #include + +-#if SHSTK_ENABLED +-/* The shadow stack prevents us from pushing the saved return PC onto +- the stack and returning normally. Instead we pop the shadow stack +- and return directly. This is the safest way to return and ensures +- any stack manipulations done by the vfork'd child doesn't cause the +- parent to terminate when CET is enabled. */ +-# undef SYSCALL_ERROR_HANDLER +-# define SYSCALL_ERROR_HANDLER \ +-0: \ +- SYSCALL_SET_ERRNO; \ +- or $-1, %RAX_LP; \ +- jmp 1b; +-# undef SYSCALL_ERROR_LABEL +-# define SYSCALL_ERROR_LABEL 0f +-#endif +- + /* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, +@@ -53,17 +37,14 @@ ENTRY (__vfork) + movl $SYS_ify (vfork), %eax + syscall + +-#if !SHSTK_ENABLED + /* Push back the return PC. */ + pushq %rdi + cfi_adjust_cfa_offset(8) +-#endif + + cmpl $-4095, %eax + jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ + + #if SHSTK_ENABLED +-1: + /* Check if shadow stack is in use. */ + xorl %esi, %esi + rdsspq %rsi +@@ -71,16 +52,19 @@ ENTRY (__vfork) + /* Normal return if shadow stack isn't in use. */ + je L(no_shstk) + +- /* Pop return address from shadow stack and jump back to caller +- directly. */ +- movl $1, %esi +- incsspq %rsi ++ testl %eax, %eax ++ /* In parent, normal return. */ ++ jnz L(no_shstk) ++ ++ /* NB: In child, jump back to caller via indirect branch without ++ popping shadow stack which is shared with parent. Keep shadow ++ stack mismatched so that child returns in the vfork-calling ++ function will trigger SIGSEGV. */ ++ popq %rdi ++ cfi_adjust_cfa_offset(-8) + jmp *%rdi + + L(no_shstk): +- /* Push back the return PC. */ +- pushq %rdi +- cfi_adjust_cfa_offset(8) + #endif + + /* Normal return. */ +-- +2.26.2 + diff --git a/SOURCES/glibc-rh1855790-2.patch b/SOURCES/glibc-rh1855790-2.patch new file mode 100644 index 0000000..4d0aed9 --- /dev/null +++ b/SOURCES/glibc-rh1855790-2.patch @@ -0,0 +1,24 @@ +commit 4031d7484ab3f6327184b5973d91f46978ebe8cf +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386/sub_n.S: Add a missing _CET_ENDBR to indirect jump target + + Add a missing _CET_ENDBR to indirect jump targe in sysdeps/i386/sub_n.S. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/i386/sub_n.S b/sysdeps/i386/sub_n.S +index ada0cf5..949958a 100644 +--- a/sysdeps/i386/sub_n.S ++++ b/sysdeps/i386/sub_n.S +@@ -91,6 +91,7 @@ L(oop): movl (%esi),%eax + movl 8(%esi),%eax + sbbl 8(%edx),%eax + movl %eax,8(%edi) ++ _CET_ENDBR + movl 12(%esi),%eax + sbbl 12(%edx),%eax + movl %eax,12(%edi) + diff --git a/SOURCES/glibc-rh1855790-3.patch b/SOURCES/glibc-rh1855790-3.patch new file mode 100644 index 0000000..490d67c --- /dev/null +++ b/SOURCES/glibc-rh1855790-3.patch @@ -0,0 +1,33 @@ +commit 825b58f3fb04781e559858510fe83a8c4bf28425 +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386-mcount.S: Add _CET_ENDBR to _mcount and __fentry__ + + Since _mcount and __fentry__ don't use ENTRY, we need to add _CET_ENDBR + by hand. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/i386/i386-mcount.S b/sysdeps/i386/i386-mcount.S +index 3db2fcd..8c8eeb8 100644 +--- a/sysdeps/i386/i386-mcount.S ++++ b/sysdeps/i386/i386-mcount.S +@@ -30,6 +30,7 @@ + .type C_SYMBOL_NAME(_mcount), @function + .align ALIGNARG(4) + C_LABEL(_mcount) ++ _CET_ENDBR + /* Save the caller-clobbered registers. */ + pushl %eax + pushl %ecx +@@ -58,6 +59,7 @@ weak_alias (_mcount, mcount) + .type C_SYMBOL_NAME(__fentry__), @function + .align ALIGNARG(4) + C_LABEL(__fentry__) ++ _CET_ENDBR + /* Save the caller-clobbered registers. */ + pushl %eax + pushl %ecx + diff --git a/SOURCES/glibc-rh1855790-4.patch b/SOURCES/glibc-rh1855790-4.patch new file mode 100644 index 0000000..cfaea33 --- /dev/null +++ b/SOURCES/glibc-rh1855790-4.patch @@ -0,0 +1,92 @@ +commit 0455f251f494d30db4b52f11b5b0b7f285f775ef +Author: H.J. Lu +Date: Sat Feb 1 05:44:55 2020 -0800 + + i386: Use ENTRY/END in assembly codes + + Use ENTRY and END in assembly codes so that ENDBR32 will be added at + function entries when CET is enabled. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/i386/nptl/pthread_spin_lock.S b/sysdeps/i386/nptl/pthread_spin_lock.S +index 1980fec..8aa081b 100644 +--- a/sysdeps/i386/nptl/pthread_spin_lock.S ++++ b/sysdeps/i386/nptl/pthread_spin_lock.S +@@ -15,12 +15,10 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + +- .globl pthread_spin_lock +- .type pthread_spin_lock,@function +- .align 16 +-pthread_spin_lock: ++ENTRY (pthread_spin_lock) + mov 4(%esp), %eax + 1: LOCK + decl 0(%eax) +@@ -34,4 +32,4 @@ pthread_spin_lock: + cmpl $0, 0(%eax) + jg 1b + jmp 2b +- .size pthread_spin_lock,.-pthread_spin_lock ++END (pthread_spin_lock) +diff --git a/sysdeps/i386/nptl/pthread_spin_unlock.S b/sysdeps/i386/nptl/pthread_spin_unlock.S +index 2e71086..2995001 100644 +--- a/sysdeps/i386/nptl/pthread_spin_unlock.S ++++ b/sysdeps/i386/nptl/pthread_spin_unlock.S +@@ -16,15 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + +- .globl pthread_spin_unlock +- .type pthread_spin_unlock,@function +- .align 16 +-pthread_spin_unlock: ++#include ++ ++ENTRY (pthread_spin_unlock) + movl 4(%esp), %eax + movl $1, (%eax) + xorl %eax, %eax + ret +- .size pthread_spin_unlock,.-pthread_spin_unlock ++END (pthread_spin_unlock) + + /* The implementation of pthread_spin_init is identical. */ + .globl pthread_spin_init +diff --git a/sysdeps/i386/pthread_spin_trylock.S b/sysdeps/i386/pthread_spin_trylock.S +index 686dd8c..42cbdb7 100644 +--- a/sysdeps/i386/pthread_spin_trylock.S ++++ b/sysdeps/i386/pthread_spin_trylock.S +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + +@@ -25,10 +26,7 @@ + # define LOCK lock + #endif + +- .globl pthread_spin_trylock +- .type pthread_spin_trylock,@function +- .align 16 +-pthread_spin_trylock: ++ENTRY (pthread_spin_trylock) + movl 4(%esp), %edx + movl $1, %eax + xorl %ecx, %ecx +@@ -43,4 +41,4 @@ pthread_spin_trylock: + 0: + #endif + ret +- .size pthread_spin_trylock,.-pthread_spin_trylock ++END (pthread_spin_trylock) + diff --git a/SOURCES/glibc-rh1855790-5.patch b/SOURCES/glibc-rh1855790-5.patch new file mode 100644 index 0000000..908ff46 --- /dev/null +++ b/SOURCES/glibc-rh1855790-5.patch @@ -0,0 +1,63 @@ +commit bbfc0f0f8e30680437d1c5b90563018bcd403881 +Author: H.J. Lu +Date: Sat Feb 1 05:44:56 2020 -0800 + + i386: Remove _exit.S + + The generic implementation is suffice since __NR_exit_group is always + support and i386 does define ABORT_INSTRUCTION. + + Reviewed-by: Adhemerval Zanella +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/_exit.S b/sysdeps/unix/sysv/linux/i386/_exit.S +deleted file mode 100644 +index a10eede..0000000 +--- a/sysdeps/unix/sysv/linux/i386/_exit.S ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* Copyright (C) 2002-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 +- . */ +- +-#include +- +- .text +- .type _exit,@function +- .global _exit +-_exit: +- movl 4(%esp), %ebx +- +- /* Try the new syscall first. */ +-#ifdef __NR_exit_group +- movl $__NR_exit_group, %eax +- ENTER_KERNEL +-#endif +- +- /* Not available. Now the old one. */ +- movl $__NR_exit, %eax +- /* Don't bother using ENTER_KERNEL here. If the exit_group +- syscall is not available AT_SYSINFO isn't either. */ +- int $0x80 +- +- /* This must not fail. Be sure we don't return. */ +- hlt +- .size _exit,.-_exit +- +-libc_hidden_def (_exit) +-rtld_hidden_def (_exit) +-weak_alias (_exit, _Exit) + diff --git a/SOURCES/glibc-rh1855790-6.patch b/SOURCES/glibc-rh1855790-6.patch new file mode 100644 index 0000000..0ecf744 --- /dev/null +++ b/SOURCES/glibc-rh1855790-6.patch @@ -0,0 +1,572 @@ +commit 5d844e1b72513cf59b5e7c14295644efdcc66e44 +Author: H.J. Lu +Date: Fri Feb 14 14:45:34 2020 -0800 + + i386: Enable CET support in ucontext functions + + 1. getcontext and swapcontext are updated to save the caller's shadow + stack pointer and return address. + 2. setcontext and swapcontext are updated to restore shadow stack and + jump to new context directly. + 3. makecontext is updated to allocate a new shadow stack and set the + caller's return address to the helper code, L(exitcode). + 4. Since we no longer save and restore EAX, ECX and EDX in getcontext, + setcontext and swapcontext, we can use them as scratch register slots + to enable CET in ucontext functions. + + Since makecontext allocates a new shadow stack when making a new + context and kernel allocates a new shadow stack for clone/fork/vfork + syscalls, we track the current shadow stack base. In setcontext and + swapcontext, if the target shadow stack base is the same as the current + shadow stack base, we unwind the shadow stack. Otherwise it is a stack + switch and we look for a restore token. + + We enable shadow stack at run-time only if program and all used shared + objects, including dlopened ones, are shadow stack enabled, which means + that they must be compiled with GCC 8 or above and glibc 2.28 or above. + We need to save and restore shadow stack only if shadow stack is enabled. + When caller of getcontext, setcontext, swapcontext and makecontext is + compiled with smaller ucontext_t, shadow stack won't be enabled at + run-time. We check if shadow stack is enabled before accessing the + extended field in ucontext_t. + + Tested on i386 CET/non-CET machines. + + Reviewed-by: Carlos O'Donell +--- + +diff --git a/sysdeps/unix/sysv/linux/i386/getcontext.S b/sysdeps/unix/sysv/linux/i386/getcontext.S +index 6637596..4ed9d03 100644 +--- a/sysdeps/unix/sysv/linux/i386/getcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/getcontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -42,6 +43,61 @@ ENTRY(__getcontext) + movw %fs, %dx + movl %edx, oFS(%eax) + ++#if SHSTK_ENABLED ++ /* Check if shadow stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(no_shstk) ++ ++ /* Save EAX in EDX. */ ++ movl %eax, %edx ++ ++ xorl %eax, %eax ++ cmpl %gs:SSP_BASE_OFFSET, %eax ++ jnz L(shadow_stack_bound_recorded) ++ ++ /* Save EBX in the first scratch register slot. */ ++ movl %ebx, oSCRATCH1(%edx) ++ ++ /* Get the base address and size of the default shadow stack ++ which must be the current shadow stack since nothing has ++ been recorded yet. */ ++ sub $24, %esp ++ mov %esp, %ecx ++ movl $ARCH_CET_STATUS, %ebx ++ movl $__NR_arch_prctl, %eax ++ ENTER_KERNEL ++ testl %eax, %eax ++ jz L(continue_no_err) ++ ++ /* This should never happen. */ ++ hlt ++ ++L(continue_no_err): ++ /* Restore EBX from the first scratch register slot. */ ++ movl oSCRATCH1(%edx), %ebx ++ ++ /* Record the base of the current shadow stack. */ ++ movl 8(%esp), %eax ++ movl %eax, %gs:SSP_BASE_OFFSET ++ add $24, %esp ++ ++L(shadow_stack_bound_recorded): ++ /* Load address of the context data structure. */ ++ movl 4(%esp), %eax ++ ++ /* Get the current shadow stack pointer. */ ++ rdsspd %edx ++ /* NB: Save the caller's shadow stack so that we can jump back ++ to the caller directly. */ ++ addl $4, %edx ++ movl %edx, oSSP(%eax) ++ ++ /* Save the current shadow stack base in ucontext. */ ++ movl %gs:SSP_BASE_OFFSET, %edx ++ movl %edx, (oSSP + 4)(%eax) ++ ++L(no_shstk): ++#endif + /* We have separate floating-point register content memory on the + stack. We use the __fpregs_mem block in the context. Set the + links up correctly. */ +diff --git a/sysdeps/unix/sysv/linux/i386/makecontext.S b/sysdeps/unix/sysv/linux/i386/makecontext.S +index e3ca3dc..2d82ddc 100644 +--- a/sysdeps/unix/sysv/linux/i386/makecontext.S ++++ b/sysdeps/unix/sysv/linux/i386/makecontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -68,6 +69,127 @@ ENTRY(__makecontext) + jnz 1b + 2: + ++#if SHSTK_ENABLED ++ /* Check if Shadow Stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(skip_ssp) ++ ++ /* Reload the pointer to ucontext. */ ++ movl 4(%esp), %eax ++ ++ /* Shadow stack is enabled. We need to allocate a new shadow ++ stack. */ ++ subl oSS_SP(%eax), %edx ++ shrl $STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT, %edx ++ ++ /* Align shadow stack size to 8 bytes. */ ++ addl $7, %edx ++ andl $-8, %edx ++ ++ /* Store shadow stack size in __ssp[2]. */ ++ movl %edx, (oSSP + 8)(%eax) ++ ++ /* Save ESI in the second scratch register slot. */ ++ movl %esi, oSCRATCH2(%eax) ++ /* Save EDI in the third scratch register slot. */ ++ movl %edi, oSCRATCH3(%eax) ++ ++ /* Save the pointer to ucontext. */ ++ movl %eax, %edi ++ ++ /* Get the original shadow stack pointer. */ ++ rdsspd %esi ++ ++ /* Align the saved original shadow stack pointer to the next ++ 8 byte aligned boundary. */ ++ andl $-8, %esi ++ ++ /* Load the top of the new stack into EDX. */ ++ movl oESP(%eax), %edx ++ ++ /* We need to terminate the FDE here because the unwinder looks ++ at ra-1 for unwind information. */ ++ cfi_endproc ++ ++ /* Swap the original stack pointer with the top of the new ++ stack. */ ++ xchgl %esp, %edx ++ ++ /* Add 4 bytes since CALL will push the 4-byte return address ++ onto stack. */ ++ addl $4, %esp ++ ++ /* Allocate the new shadow stack. Save EBX in the first scratch ++ register slot. */ ++ movl %ebx, oSCRATCH1(%eax) ++ ++ /* CET syscall takes 64-bit sizes. */ ++ subl $16, %esp ++ movl (oSSP + 8)(%eax), %ecx ++ movl %ecx, (%esp) ++ movl $0, 4(%esp) ++ movl %ecx, 8(%esp) ++ movl $0, 12(%esp) ++ movl %esp, %ecx ++ ++ movl $ARCH_CET_ALLOC_SHSTK, %ebx ++ movl $__NR_arch_prctl, %eax ++ ENTER_KERNEL ++ testl %eax, %eax ++ jne L(hlt) /* This should never happen. */ ++ ++ /* Copy the base address of the new shadow stack to __ssp[1]. */ ++ movl (%esp), %eax ++ movl %eax, (oSSP + 4)(%edi) ++ ++ addl $16, %esp ++ ++ /* Restore EBX from the first scratch register slot. */ ++ movl oSCRATCH1(%edi), %ebx ++ ++ /* Get the size of the new shadow stack. */ ++ movl (oSSP + 8)(%edi), %ecx ++ ++ /* Use the restore stoken to restore the new shadow stack. */ ++ rstorssp -8(%eax, %ecx) ++ ++ /* Save the restore token at the next 8 byte aligned boundary ++ on the original shadow stack. */ ++ saveprevssp ++ ++ /* Push the address of "jmp exitcode" onto the new stack as ++ well as the new shadow stack. */ ++ call 1f ++ jmp L(exitcode) ++1: ++ ++ /* Get the new shadow stack pointer. */ ++ rdsspd %eax ++ ++ /* Use the restore stoken to restore the original shadow stack. */ ++ rstorssp -8(%esi) ++ ++ /* Save the restore token on the new shadow stack. */ ++ saveprevssp ++ ++ /* Store the new shadow stack pointer in __ssp[0]. */ ++ movl %eax, oSSP(%edi) ++ ++ /* Restore the original stack. */ ++ mov %edx, %esp ++ ++ cfi_startproc ++ ++ /* Restore ESI from the second scratch register slot. */ ++ movl oSCRATCH2(%edi), %esi ++ /* Restore EDI from the third scratch register slot. */ ++ movl oSCRATCH3(%edi), %edi ++ ++ ret ++ ++L(skip_ssp): ++#endif ++ + /* If the function we call returns we must continue with the + context which is given in the uc_link element. To do this + set the return address for the function the user provides +@@ -123,6 +245,7 @@ L(call_exit): + call HIDDEN_JUMPTARGET(exit) + /* The 'exit' call should never return. In case it does cause + the process to terminate. */ ++L(hlt): + hlt + cfi_startproc + END(__makecontext) +diff --git a/sysdeps/unix/sysv/linux/i386/setcontext.S b/sysdeps/unix/sysv/linux/i386/setcontext.S +index 7565d7d..7b58918 100644 +--- a/sysdeps/unix/sysv/linux/i386/setcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/setcontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -56,9 +57,6 @@ ENTRY(__setcontext) + movl oFS(%eax), %ecx + movw %cx, %fs + +- /* Fetch the address to return to. */ +- movl oEIP(%eax), %ecx +- + /* Load the new stack pointer. */ + cfi_def_cfa (eax, 0) + cfi_offset (edi, oEDI) +@@ -67,6 +65,103 @@ ENTRY(__setcontext) + cfi_offset (ebx, oEBX) + movl oESP(%eax), %esp + ++#if SHSTK_ENABLED ++ /* Check if Shadow Stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(no_shstk) ++ ++ /* If the base of the target shadow stack is the same as the ++ base of the current shadow stack, we unwind the shadow ++ stack. Otherwise it is a stack switch and we look for a ++ restore token. */ ++ movl oSSP(%eax), %esi ++ movl %esi, %edi ++ ++ /* Get the base of the target shadow stack. */ ++ movl (oSSP + 4)(%eax), %ecx ++ cmpl %gs:SSP_BASE_OFFSET, %ecx ++ je L(unwind_shadow_stack) ++ ++ /* Align the saved original shadow stack pointer to the next ++ 8 byte aligned boundary. */ ++ andl $-8, %esi ++ ++L(find_restore_token_loop): ++ /* Look for a restore token. */ ++ movl -8(%esi), %ebx ++ andl $-8, %ebx ++ cmpl %esi, %ebx ++ je L(restore_shadow_stack) ++ ++ /* Try the next slot. */ ++ subl $8, %esi ++ jmp L(find_restore_token_loop) ++ ++L(restore_shadow_stack): ++ /* Pop return address from the shadow stack since setcontext ++ will not return. */ ++ movl $1, %ebx ++ incsspd %ebx ++ ++ /* Use the restore stoken to restore the target shadow stack. */ ++ rstorssp -8(%esi) ++ ++ /* Save the restore token on the old shadow stack. NB: This ++ restore token may be checked by setcontext or swapcontext ++ later. */ ++ saveprevssp ++ ++ /* Record the new shadow stack base that was switched to. */ ++ movl (oSSP + 4)(%eax), %ebx ++ movl %ebx, %gs:SSP_BASE_OFFSET ++ ++L(unwind_shadow_stack): ++ rdsspd %ebx ++ subl %edi, %ebx ++ je L(skip_unwind_shadow_stack) ++ negl %ebx ++ shrl $2, %ebx ++ movl $255, %esi ++L(loop): ++ cmpl %esi, %ebx ++ cmovb %ebx, %esi ++ incsspd %esi ++ subl %esi, %ebx ++ ja L(loop) ++ ++L(skip_unwind_shadow_stack): ++ ++ /* Load the values of all the preserved registers (except ESP). */ ++ movl oEDI(%eax), %edi ++ movl oESI(%eax), %esi ++ movl oEBP(%eax), %ebp ++ movl oEBX(%eax), %ebx ++ ++ /* Get the return address set with getcontext. */ ++ movl oEIP(%eax), %ecx ++ ++ /* Check if return address is valid for the case when setcontext ++ is invoked from L(exitcode) with linked context. */ ++ rdsspd %eax ++ cmpl (%eax), %ecx ++ /* Clear EAX to indicate success. NB: Don't use xorl to keep ++ EFLAGS for jne. */ ++ movl $0, %eax ++ jne L(jmp) ++ /* Return to the new context if return address valid. */ ++ pushl %ecx ++ ret ++ ++L(jmp): ++ /* Jump to the new context directly. */ ++ jmp *%ecx ++ ++L(no_shstk): ++#endif ++ ++ /* Fetch the address to return to. */ ++ movl oEIP(%eax), %ecx ++ + /* Push the return address on the new stack so we can return there. */ + pushl %ecx + +diff --git a/sysdeps/unix/sysv/linux/i386/swapcontext.S b/sysdeps/unix/sysv/linux/i386/swapcontext.S +index ce27d51..d1b648c 100644 +--- a/sysdeps/unix/sysv/linux/i386/swapcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/swapcontext.S +@@ -18,6 +18,7 @@ + . */ + + #include ++#include + + #include "ucontext_i.h" + +@@ -76,6 +77,144 @@ ENTRY(__swapcontext) + movl oFS(%eax), %edx + movw %dx, %fs + ++#if SHSTK_ENABLED ++ /* Check if Shadow Stack is enabled. */ ++ testl $X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET ++ jz L(no_shstk) ++ ++ xorl %eax, %eax ++ cmpl %gs:SSP_BASE_OFFSET, %eax ++ jnz L(shadow_stack_bound_recorded) ++ ++ /* Get the base address and size of the default shadow stack ++ which must be the current shadow stack since nothing has ++ been recorded yet. */ ++ sub $24, %esp ++ mov %esp, %ecx ++ movl $ARCH_CET_STATUS, %ebx ++ movl $__NR_arch_prctl, %eax ++ ENTER_KERNEL ++ testl %eax, %eax ++ jz L(continue_no_err) ++ ++ /* This should never happen. */ ++ hlt ++ ++L(continue_no_err): ++ /* Record the base of the current shadow stack. */ ++ movl 8(%esp), %eax ++ movl %eax, %gs:SSP_BASE_OFFSET ++ add $24, %esp ++ ++L(shadow_stack_bound_recorded): ++ /* Load address of the context data structure we save in. */ ++ movl 4(%esp), %eax ++ ++ /* Load address of the context data structure we swap in */ ++ movl 8(%esp), %edx ++ ++ /* If we unwind the stack, we can't undo stack unwinding. Just ++ save the target shadow stack pointer as the current shadow ++ stack pointer. */ ++ movl oSSP(%edx), %ecx ++ movl %ecx, oSSP(%eax) ++ ++ /* Save the current shadow stack base in ucontext. */ ++ movl %gs:SSP_BASE_OFFSET, %ecx ++ movl %ecx, (oSSP + 4)(%eax) ++ ++ /* If the base of the target shadow stack is the same as the ++ base of the current shadow stack, we unwind the shadow ++ stack. Otherwise it is a stack switch and we look for a ++ restore token. */ ++ movl oSSP(%edx), %esi ++ movl %esi, %edi ++ ++ /* Get the base of the target shadow stack. */ ++ movl (oSSP + 4)(%edx), %ecx ++ cmpl %gs:SSP_BASE_OFFSET, %ecx ++ je L(unwind_shadow_stack) ++ ++ /* Align the saved original shadow stack pointer to the next ++ 8 byte aligned boundary. */ ++ andl $-8, %esi ++ ++L(find_restore_token_loop): ++ /* Look for a restore token. */ ++ movl -8(%esi), %ebx ++ andl $-8, %ebx ++ cmpl %esi, %ebx ++ je L(restore_shadow_stack) ++ ++ /* Try the next slot. */ ++ subl $8, %esi ++ jmp L(find_restore_token_loop) ++ ++L(restore_shadow_stack): ++ /* The target shadow stack will be restored. Save the current ++ shadow stack pointer. */ ++ rdsspd %ecx ++ movl %ecx, oSSP(%eax) ++ ++ /* Use the restore stoken to restore the target shadow stack. */ ++ rstorssp -8(%esi) ++ ++ /* Save the restore token on the old shadow stack. NB: This ++ restore token may be checked by setcontext or swapcontext ++ later. */ ++ saveprevssp ++ ++ /* Record the new shadow stack base that was switched to. */ ++ movl (oSSP + 4)(%edx), %ebx ++ movl %ebx, %gs:SSP_BASE_OFFSET ++ ++L(unwind_shadow_stack): ++ rdsspd %ebx ++ subl %edi, %ebx ++ je L(skip_unwind_shadow_stack) ++ negl %ebx ++ shrl $2, %ebx ++ movl $255, %esi ++L(loop): ++ cmpl %esi, %ebx ++ cmovb %ebx, %esi ++ incsspd %esi ++ subl %esi, %ebx ++ ja L(loop) ++ ++L(skip_unwind_shadow_stack): ++ ++ /* Load the new stack pointer. */ ++ movl oESP(%edx), %esp ++ ++ /* Load the values of all the preserved registers (except ESP). */ ++ movl oEDI(%edx), %edi ++ movl oESI(%edx), %esi ++ movl oEBP(%edx), %ebp ++ movl oEBX(%edx), %ebx ++ ++ /* Get the return address set with getcontext. */ ++ movl oEIP(%edx), %ecx ++ ++ /* Check if return address is valid for the case when setcontext ++ is invoked from L(exitcode) with linked context. */ ++ rdsspd %eax ++ cmpl (%eax), %ecx ++ /* Clear EAX to indicate success. NB: Don't use xorl to keep ++ EFLAGS for jne. */ ++ movl $0, %eax ++ jne L(jmp) ++ /* Return to the new context if return address valid. */ ++ pushl %ecx ++ ret ++ ++L(jmp): ++ /* Jump to the new context directly. */ ++ jmp *%ecx ++ ++L(no_shstk): ++#endif ++ + /* Fetch the address to return to. */ + movl oEIP(%eax), %ecx + +diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h +index 3255cc7..9344ac7 100644 +--- a/sysdeps/unix/sysv/linux/i386/sysdep.h ++++ b/sysdeps/unix/sysv/linux/i386/sysdep.h +@@ -656,4 +656,9 @@ struct libc_do_syscall_args + # endif + #endif + ++/* Each shadow stack slot takes 4 bytes. Assuming that each stack ++ frame takes 128 bytes, this is used to compute shadow stack size ++ from stack size. */ ++#define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5 ++ + #endif /* linux/i386/sysdep.h */ +diff --git a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +index 1dfe03d..1d8608e 100644 +--- a/sysdeps/unix/sysv/linux/i386/ucontext_i.sym ++++ b/sysdeps/unix/sysv/linux/i386/ucontext_i.sym +@@ -22,6 +22,10 @@ oEBP mreg (EBP) + oESP mreg (ESP) + oEBX mreg (EBX) + oEIP mreg (EIP) ++oSCRATCH1 mreg (EAX) ++oSCRATCH2 mreg (ECX) ++oSCRATCH3 mreg (EDX) + oFPREGS mcontext (fpregs) + oSIGMASK ucontext (uc_sigmask) + oFPREGSMEM ucontext (__fpregs_mem) ++oSSP ucontext (__ssp) + diff --git a/SOURCES/glibc-rh1855790-7.patch b/SOURCES/glibc-rh1855790-7.patch new file mode 100644 index 0000000..990df57 --- /dev/null +++ b/SOURCES/glibc-rh1855790-7.patch @@ -0,0 +1,574 @@ +commit 1fabdb99084df004f7f4cdc7068d1be209a258be +Author: H.J. Lu +Date: Wed Mar 18 04:35:54 2020 -0700 + + x86: Remove ARCH_CET_LEGACY_BITMAP [BZ #25397] + + Since legacy bitmap doesn't cover jitted code generated by legacy JIT + engine, it isn't very useful. This patch removes ARCH_CET_LEGACY_BITMAP + and treats indirect branch tracking similar to shadow stack by removing + legacy bitmap support. + + Tested on CET Linux/x86-64 and non-CET Linux/x86-64. + + Reviewed-by: Carlos O'Donell +--- + +diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.h b/sysdeps/unix/sysv/linux/x86/dl-cet.h +index 3fbcfeb..47c52e6 100644 +--- a/sysdeps/unix/sysv/linux/x86/dl-cet.h ++++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h +@@ -19,27 +19,6 @@ + #include + + static inline int __attribute__ ((always_inline)) +-dl_cet_allocate_legacy_bitmap (unsigned long *legacy_bitmap) +-{ +- /* Allocate legacy bitmap. */ +- INTERNAL_SYSCALL_DECL (err); +-#ifdef __LP64__ +- return (int) INTERNAL_SYSCALL (arch_prctl, err, 2, +- ARCH_CET_LEGACY_BITMAP, legacy_bitmap); +-#else +- unsigned long long legacy_bitmap_u64[2]; +- int res = INTERNAL_SYSCALL (arch_prctl, err, 2, +- ARCH_CET_LEGACY_BITMAP, legacy_bitmap_u64); +- if (res == 0) +- { +- legacy_bitmap[0] = legacy_bitmap_u64[0]; +- legacy_bitmap[1] = legacy_bitmap_u64[1]; +- } +- return res; +-#endif +-} +- +-static inline int __attribute__ ((always_inline)) + dl_cet_disable_cet (unsigned int cet_feature) + { + INTERNAL_SYSCALL_DECL (err); +diff --git a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +index f67f329..45ad0b0 100644 +--- a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h ++++ b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +@@ -24,9 +24,4 @@ + OUT: allocated shadow stack address: *addr. + */ + # define ARCH_CET_ALLOC_SHSTK 0x3004 +-/* Return legacy region bitmap info in unsigned long long *addr: +- address: addr[0]. +- size: addr[1]. +- */ +-# define ARCH_CET_LEGACY_BITMAP 0x3005 + #endif /* ARCH_CET_STATUS */ +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 43ad4a7..d9bdf0b 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -20,7 +20,8 @@ sysdep-dl-routines += dl-cet + + tests += tst-cet-legacy-1 tst-cet-legacy-2 tst-cet-legacy-2a \ + tst-cet-legacy-3 tst-cet-legacy-4 \ +- tst-cet-legacy-5a tst-cet-legacy-6a ++ tst-cet-legacy-5a tst-cet-legacy-6a tst-cet-legacy-7 \ ++ tst-cet-legacy-8 + ifneq (no,$(have-tunables)) + tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ + tst-cet-legacy-5b tst-cet-legacy-6b +@@ -42,14 +43,16 @@ CFLAGS-tst-cet-legacy-4b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-5a.c += -fcf-protection + CFLAGS-tst-cet-legacy-5b.c += -fcf-protection +-CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection + CFLAGS-tst-cet-legacy-6a.c += -fcf-protection + CFLAGS-tst-cet-legacy-6b.c += -fcf-protection +-CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=branch + CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection + CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection ++CFLAGS-tst-cet-legacy-7.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-8.c += -mshstk + + $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ + $(objpfx)tst-cet-legacy-mod-2.so +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index b82ba14..627d937 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -33,63 +33,6 @@ + # 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 +@@ -117,6 +60,8 @@ dl_cet_check (struct link_map *m, const char *program) + if (ibt_enabled || shstk_enabled) + { + struct link_map *l = NULL; ++ unsigned int ibt_legacy = 0, shstk_legacy = 0; ++ bool found_ibt_legacy = false, found_shstk_legacy = false; + + /* Check if IBT and SHSTK are enabled in object. */ + bool enable_ibt = (ibt_enabled +@@ -142,10 +87,7 @@ dl_cet_check (struct link_map *m, const char *program) + 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) +@@ -167,91 +109,25 @@ dl_cet_check (struct link_map *m, const char *program) + continue; + #endif + +- if (enable_ibt +- && enable_ibt_type != CET_ALWAYS_ON +- && !(l->l_cet & lc_ibt)) ++ /* IBT is enabled only if it is enabled in executable as ++ well as all shared objects. */ ++ enable_ibt &= (enable_ibt_type == CET_ALWAYS_ON ++ || (l->l_cet & lc_ibt) != 0); ++ if (!found_ibt_legacy && enable_ibt != ibt_enabled) + { +- /* Remember the first and last legacy objects. */ +- if (!need_legacy_bitmap) +- last_legacy = i; +- first_legacy = i; +- need_legacy_bitmap = true; ++ found_ibt_legacy = true; ++ ibt_legacy = i; + } + + /* 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 ++ if (enable_shstk != shstk_enabled) + { +- /* 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")); +- } ++ found_shstk_legacy = true; ++ shstk_legacy = i; + } +- +- /* 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; + } + } + +@@ -259,23 +135,40 @@ mprotect_failure: + + if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled) + { +- if (!program +- && enable_shstk_type != CET_PERMISSIVE) ++ if (!program) + { +- /* 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; ++ if (enable_ibt_type != CET_PERMISSIVE) ++ { ++ /* When IBT is enabled, we cannot dlopen a shared ++ object without IBT. */ ++ if (found_ibt_legacy) ++ _dl_signal_error (0, ++ m->l_initfini[ibt_legacy]->l_name, ++ "dlopen", ++ N_("rebuild shared object with IBT support enabled")); ++ } ++ ++ if (enable_shstk_type != CET_PERMISSIVE) ++ { ++ /* When SHSTK is enabled, we cannot dlopen a shared ++ object without SHSTK. */ ++ if (found_shstk_legacy) ++ _dl_signal_error (0, ++ m->l_initfini[shstk_legacy]->l_name, ++ "dlopen", ++ N_("rebuild shared object with SHSTK support enabled")); ++ } ++ ++ if (enable_ibt_type != CET_PERMISSIVE ++ && enable_shstk_type != CET_PERMISSIVE) ++ 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) ++ if (!enable_ibt) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; + if (!enable_shstk) + cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; +@@ -286,8 +179,14 @@ mprotect_failure: + 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")); ++ { ++ if (found_ibt_legacy) ++ l = m->l_initfini[ibt_legacy]; ++ else ++ l = m->l_initfini[shstk_legacy]; ++ _dl_signal_error (-res, l->l_name, "dlopen", ++ N_("can't disable CET")); ++ } + } + + /* Clear the disabled bits in dl_x86_feature_1. */ +@@ -297,17 +196,21 @@ mprotect_failure: + } + + #ifdef SHARED +- if (program +- && (!shstk_enabled +- || enable_shstk_type != CET_PERMISSIVE) +- && (ibt_enabled || shstk_enabled)) ++ if (program && (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); ++ if ((!ibt_enabled ++ || enable_ibt_type != CET_PERMISSIVE) ++ && (!shstk_enabled ++ || enable_shstk_type != CET_PERMISSIVE)) ++ { ++ /* Lock CET if IBT or SHSTK is enabled in executable unless ++ IBT or SHSTK is enabled permissively. */ ++ int res = dl_cet_lock_cet (); ++ if (res != 0) ++ _dl_fatal_printf ("%s: can't lock CET\n", program); ++ } + ++ /* Set feature_1 if IBT or SHSTK is enabled in executable. */ + cet_feature_changed = true; + } + #endif +diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c +index eddbde6..920bfe8 100644 +--- a/sysdeps/x86/dl-procruntime.c ++++ b/sysdeps/x86/dl-procruntime.c +@@ -54,15 +54,4 @@ PROCINFO_CLASS unsigned int _dl_x86_feature_1[2] + # else + , + # endif +- +-# if !defined PROCINFO_DECL && defined SHARED +- ._dl_x86_legacy_bitmap +-# else +-PROCINFO_CLASS unsigned long _dl_x86_legacy_bitmap[2] +-# endif +-# if !defined SHARED || defined PROCINFO_DECL +-; +-# else +-, +-# endif + #endif +diff --git a/sysdeps/x86/tst-cet-legacy-4.c b/sysdeps/x86/tst-cet-legacy-4.c +index 3ead63d..f0ba326 100644 +--- a/sysdeps/x86/tst-cet-legacy-4.c ++++ b/sysdeps/x86/tst-cet-legacy-4.c +@@ -20,6 +20,9 @@ + #include + #include + #include ++#include ++ ++#include + + static int + do_test (void) +@@ -31,22 +34,18 @@ do_test (void) + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { +- printf ("cannot open '%s': %s\n", modname, dlerror ()); +- exit (1); ++ const char *err = dlerror (); ++ if (!strstr (err, "rebuild shared object with IBT support enabled")) ++ FAIL_EXIT1 ("incorrect dlopen '%s' error: %s\n", modname, err); ++ return 0; + } + + fp = dlsym (h, "test"); + if (fp == NULL) +- { +- printf ("cannot get symbol 'test': %s\n", dlerror ()); +- exit (1); +- } ++ FAIL_EXIT1 ("cannot get symbol 'test': %s\n", dlerror ()); + + if (fp () != 0) +- { +- puts ("test () != 0"); +- exit (1); +- } ++ FAIL_EXIT1 ("test () != 0"); + + dlclose (h); + +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +index fbf640f..e1ca09d 100644 +--- a/sysdeps/x86/tst-cet-legacy-5.c ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -35,7 +35,8 @@ do_test_1 (const char *modname, bool fail) + if (fail) + { + const char *err = dlerror (); +- if (strstr (err, "shadow stack isn't enabled") == NULL) ++ if (strstr (err, "rebuild shared object with SHSTK support enabled") ++ == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, + dlerror ()); +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +index 9151225..184a35b 100644 +--- a/sysdeps/x86/tst-cet-legacy-6.c ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -35,7 +35,8 @@ do_test_1 (const char *modname, bool fail) + if (fail) + { + const char *err = dlerror (); +- if (strstr (err, "shadow stack isn't enabled") == NULL) ++ if (strstr (err, "rebuild shared object with SHSTK support enabled") ++ == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, + dlerror ()); +diff --git a/sysdeps/x86/tst-cet-legacy-7.c b/sysdeps/x86/tst-cet-legacy-7.c +new file mode 100644 +index 0000000..58bcb29 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-7.c +@@ -0,0 +1,38 @@ ++/* Check compatibility of legacy executable with a JIT engine. ++ Copyright (C) 2020 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Check that mmapped legacy code works with -fcf-protection=none. */ ++ ++static int ++do_test (void) ++{ ++ void (*funcp) (void); ++ funcp = xmmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_PRIVATE, -1); ++ printf ("mmap = %p\n", funcp); ++ /* Write RET instruction. */ ++ *(char *) funcp = 0xc3; ++ funcp (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-cet-legacy-8.c b/sysdeps/x86/tst-cet-legacy-8.c +new file mode 100644 +index 0000000..11e8115 +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-8.c +@@ -0,0 +1,48 @@ ++/* Check incompatibility with legacy JIT engine. ++ Copyright (C) 2020 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Check that mmapped legacy code trigges segfault with -fcf-protection. */ ++ ++static int ++do_test (void) ++{ ++ /* NB: This test should trigger SIGSEGV on CET platforms. If SHSTK ++ is disabled, assuming IBT is also disabled. */ ++ if (_get_ssp () == 0) ++ return EXIT_UNSUPPORTED; ++ ++ void (*funcp) (void); ++ funcp = xmmap (NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_PRIVATE, -1); ++ printf ("mmap = %p\n", funcp); ++ /* Write RET instruction. */ ++ *(char *) funcp = 0xc3; ++ funcp (); ++ return EXIT_FAILURE; ++} ++ ++#define EXPECTED_SIGNAL (_get_ssp () == 0 ? 0 : SIGSEGV) ++#include + diff --git a/SOURCES/glibc-rh1855790-8.patch b/SOURCES/glibc-rh1855790-8.patch new file mode 100644 index 0000000..47c212d --- /dev/null +++ b/SOURCES/glibc-rh1855790-8.patch @@ -0,0 +1,420 @@ +commit 674ea88294bfb8d89878a0ebbbcec38a85e118a5 +Author: H.J. Lu +Date: Tue Apr 28 10:05:25 2020 -0700 + + x86: Move CET control to _dl_x86_feature_control [BZ #25887] + + 1. Include to get architecture specific initializer in + rtld_global. + 2. Change _dl_x86_feature_1[2] to _dl_x86_feature_1. + 3. Add _dl_x86_feature_control after _dl_x86_feature_1, which is a + struct of 2 bitfields for IBT and SHSTK control + + This fixes [BZ #25887]. +--- + +diff --git a/elf/rtld.c b/elf/rtld.c +index e107bd1..7f030f7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -230,6 +230,8 @@ rtld_hidden_def (_dl_starting_up) + (except those which cannot be added for some reason). */ + struct rtld_global _rtld_global = + { ++ /* Get architecture specific initializer. */ ++#include + /* Generally the default presumption without further information is an + * executable stack but this is not true for all platforms. */ + ._dl_stack_flags = DEFAULT_STACK_PERMS, +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index f6cfb90..8c959e3 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -71,7 +71,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; + /* Check if SHSTK is enabled by kernel. */ + bool shstk_enabled +- = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; ++ = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; + + if (l->l_info[DT_JMPREL] && lazy) + { +diff --git a/sysdeps/unix/sysv/linux/x86/cpu-features.c b/sysdeps/unix/sysv/linux/x86/cpu-features.c +index 8566a26..9f40624 100644 +--- a/sysdeps/unix/sysv/linux/x86/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/x86/cpu-features.c +@@ -36,7 +36,7 @@ static inline void + x86_setup_tls (void) + { + __libc_setup_tls (); +- THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)[0]); ++ THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); + } + + # define ARCH_SETUP_TLS() x86_setup_tls () +diff --git a/sysdeps/x86/cet-control.h b/sysdeps/x86/cet-control.h +new file mode 100644 +index 0000000..7b29f95 +--- /dev/null ++++ b/sysdeps/x86/cet-control.h +@@ -0,0 +1,41 @@ ++/* 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 ++ . */ ++ ++#ifndef _CET_CONTROL_H ++#define _CET_CONTROL_H ++ ++/* For each CET feature, IBT and SHSTK, valid control values. */ ++enum dl_x86_cet_control ++{ ++ /* Enable CET features based on ELF property note. */ ++ cet_elf_property = 0, ++ /* Always enable CET features. */ ++ cet_always_on, ++ /* Always disable CET features. */ ++ cet_always_off, ++ /* Enable CET features permissively. */ ++ cet_permissive ++}; ++ ++struct dl_x86_feature_control ++{ ++ enum dl_x86_cet_control ibt : 2; ++ enum dl_x86_cet_control shstk : 2; ++}; ++ ++#endif /* cet-control.h */ +diff --git a/sysdeps/x86/cet-tunables.h b/sysdeps/x86/cet-tunables.h +deleted file mode 100644 +index ca02305..0000000 +--- a/sysdeps/x86/cet-tunables.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* 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 +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 4695ac8..ac74f40 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -39,7 +39,6 @@ extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *) + + #if CET_ENABLED + # include +-# include + #endif + + static void +@@ -490,7 +489,7 @@ no_cpuid: + + if (cet_status) + { +- GL(dl_x86_feature_1)[0] = cet_status; ++ GL(dl_x86_feature_1) = cet_status; + + # ifndef SHARED + /* Check if IBT and SHSTK are enabled by kernel. */ +@@ -514,14 +513,13 @@ no_cpuid: + + /* Clear the disabled bits in dl_x86_feature_1. */ + if (res == 0) +- GL(dl_x86_feature_1)[0] &= ~cet_feature; ++ GL(dl_x86_feature_1) &= ~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) ++ lock CET if IBT or SHSTK is enabled permissively. */ ++ if (GL(dl_x86_feature_control).ibt != cet_permissive ++ && GL(dl_x86_feature_control).shstk != cet_permissive) + dl_cet_lock_cet (); + } + # endif +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 69155a8..fad6726 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -336,28 +336,18 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + } + + # if CET_ENABLED +-# 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; +- } ++ GL(dl_x86_feature_control).ibt = 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; +- } ++ GL(dl_x86_feature_control).ibt = 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; +- } ++ GL(dl_x86_feature_control).ibt = cet_permissive; + } + + attribute_hidden +@@ -365,21 +355,12 @@ 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); +- } ++ GL(dl_x86_feature_control).shstk = cet_always_on; + 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); +- } ++ GL(dl_x86_feature_control).shstk = cet_always_off; + 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); +- } ++ GL(dl_x86_feature_control).shstk = cet_permissive; + } + # endif + #endif +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 627d937..ebc0d57 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + + /* GNU_PROPERTY_X86_FEATURE_1_IBT and GNU_PROPERTY_X86_FEATURE_1_SHSTK + are defined in , which are only available for C sources. +@@ -39,23 +38,23 @@ 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); ++ enum dl_x86_cet_control enable_ibt_type ++ = GL(dl_x86_feature_control).ibt; + /* Check how SHSTK should be enabled. */ +- unsigned int enable_shstk_type +- = ((GL(dl_x86_feature_1)[1] >> CET_MAX) & ((1 << CET_MAX) - 1)); ++ enum dl_x86_cet_control enable_shstk_type ++ = GL(dl_x86_feature_control).shstk; + + /* 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) ++ 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; ++ = (GL(dl_x86_feature_1) & 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; ++ = (GL(dl_x86_feature_1) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; + + if (ibt_enabled || shstk_enabled) + { +@@ -65,9 +64,9 @@ dl_cet_check (struct link_map *m, const char *program) + + /* Check if IBT and SHSTK are enabled in object. */ + bool enable_ibt = (ibt_enabled +- && enable_ibt_type != CET_ALWAYS_OFF); ++ && enable_ibt_type != cet_always_off); + bool enable_shstk = (shstk_enabled +- && enable_shstk_type != CET_ALWAYS_OFF); ++ && enable_shstk_type != cet_always_off); + if (program) + { + /* Enable IBT and SHSTK only if they are enabled in executable. +@@ -76,10 +75,10 @@ dl_cet_check (struct link_map *m, const char *program) + GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK + */ + enable_ibt &= (HAS_CPU_FEATURE (IBT) +- && (enable_ibt_type == CET_ALWAYS_ON ++ && (enable_ibt_type == cet_always_on + || (m->l_cet & lc_ibt) != 0)); + enable_shstk &= (HAS_CPU_FEATURE (SHSTK) +- && (enable_shstk_type == CET_ALWAYS_ON ++ && (enable_shstk_type == cet_always_on + || (m->l_cet & lc_shstk) != 0)); + } + +@@ -111,7 +110,7 @@ dl_cet_check (struct link_map *m, const char *program) + + /* IBT is enabled only if it is enabled in executable as + well as all shared objects. */ +- enable_ibt &= (enable_ibt_type == CET_ALWAYS_ON ++ enable_ibt &= (enable_ibt_type == cet_always_on + || (l->l_cet & lc_ibt) != 0); + if (!found_ibt_legacy && enable_ibt != ibt_enabled) + { +@@ -121,7 +120,7 @@ dl_cet_check (struct link_map *m, const char *program) + + /* SHSTK is enabled only if it is enabled in executable as + well as all shared objects. */ +- enable_shstk &= (enable_shstk_type == CET_ALWAYS_ON ++ enable_shstk &= (enable_shstk_type == cet_always_on + || (l->l_cet & lc_shstk) != 0); + if (enable_shstk != shstk_enabled) + { +@@ -137,7 +136,7 @@ dl_cet_check (struct link_map *m, const char *program) + { + if (!program) + { +- if (enable_ibt_type != CET_PERMISSIVE) ++ if (enable_ibt_type != cet_permissive) + { + /* When IBT is enabled, we cannot dlopen a shared + object without IBT. */ +@@ -148,7 +147,7 @@ dl_cet_check (struct link_map *m, const char *program) + N_("rebuild shared object with IBT support enabled")); + } + +- if (enable_shstk_type != CET_PERMISSIVE) ++ if (enable_shstk_type != cet_permissive) + { + /* When SHSTK is enabled, we cannot dlopen a shared + object without SHSTK. */ +@@ -159,8 +158,8 @@ dl_cet_check (struct link_map *m, const char *program) + N_("rebuild shared object with SHSTK support enabled")); + } + +- if (enable_ibt_type != CET_PERMISSIVE +- && enable_shstk_type != CET_PERMISSIVE) ++ if (enable_ibt_type != cet_permissive ++ && enable_shstk_type != cet_permissive) + return; + } + +@@ -190,7 +189,7 @@ dl_cet_check (struct link_map *m, const char *program) + } + + /* Clear the disabled bits in dl_x86_feature_1. */ +- GL(dl_x86_feature_1)[0] &= ~cet_feature; ++ GL(dl_x86_feature_1) &= ~cet_feature; + + cet_feature_changed = true; + } +@@ -199,9 +198,9 @@ dl_cet_check (struct link_map *m, const char *program) + if (program && (ibt_enabled || shstk_enabled)) + { + if ((!ibt_enabled +- || enable_ibt_type != CET_PERMISSIVE) ++ || enable_ibt_type != cet_permissive) + && (!shstk_enabled +- || enable_shstk_type != CET_PERMISSIVE)) ++ || enable_shstk_type != cet_permissive)) + { + /* Lock CET if IBT or SHSTK is enabled in executable unless + IBT or SHSTK is enabled permissively. */ +diff --git a/sysdeps/x86/dl-procruntime.c b/sysdeps/x86/dl-procruntime.c +index 920bfe8..26b2b39 100644 +--- a/sysdeps/x86/dl-procruntime.c ++++ b/sysdeps/x86/dl-procruntime.c +@@ -47,7 +47,27 @@ + # if !defined PROCINFO_DECL && defined SHARED + ._dl_x86_feature_1 + # else +-PROCINFO_CLASS unsigned int _dl_x86_feature_1[2] ++PROCINFO_CLASS unsigned int _dl_x86_feature_1 ++# endif ++# ifndef PROCINFO_DECL ++= 0 ++# endif ++# if !defined SHARED || defined PROCINFO_DECL ++; ++# else ++, ++# endif ++ ++# if !defined PROCINFO_DECL && defined SHARED ++ ._dl_x86_feature_control ++# else ++PROCINFO_CLASS struct dl_x86_feature_control _dl_x86_feature_control ++# endif ++# ifndef PROCINFO_DECL ++= { ++ .ibt = cet_elf_property, ++ .shstk = cet_elf_property ++ } + # endif + # if !defined SHARED || defined PROCINFO_DECL + ; +diff --git a/sysdeps/x86/ldsodefs.h b/sysdeps/x86/ldsodefs.h +index 0616215..54f6864 100644 +--- a/sysdeps/x86/ldsodefs.h ++++ b/sysdeps/x86/ldsodefs.h +@@ -61,6 +61,7 @@ struct La_x32_retval; + struct La_x86_64_retval *, \ + const char *) + ++#include + #include_next + + #endif + diff --git a/SOURCES/glibc-rh1855790-9.patch b/SOURCES/glibc-rh1855790-9.patch new file mode 100644 index 0000000..a4e0e49 --- /dev/null +++ b/SOURCES/glibc-rh1855790-9.patch @@ -0,0 +1,42 @@ +commit 635d6fae03257129b4672591b700a495cb6cb6c7 +Author: H.J. Lu +Date: Sat Feb 1 05:43:34 2020 -0800 + + x86: Don't make 2 calls to dlerror () in a row + + We shouldn't make 2 calls to dlerror () in a row since the first call + will clear the error. We should just use the return value from the + first call. + + Tested on Linux/x86-64. + + Reviewed-by: Florian Weimer +--- + +diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c +index e1ca09d..0a34d37 100644 +--- a/sysdeps/x86/tst-cet-legacy-5.c ++++ b/sysdeps/x86/tst-cet-legacy-5.c +@@ -39,7 +39,7 @@ do_test_1 (const char *modname, bool fail) + == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, +- dlerror ()); ++ err); + exit (1); + } + +diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c +index 184a35b..bd45218 100644 +--- a/sysdeps/x86/tst-cet-legacy-6.c ++++ b/sysdeps/x86/tst-cet-legacy-6.c +@@ -39,7 +39,7 @@ do_test_1 (const char *modname, bool fail) + == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, +- dlerror ()); ++ err); + exit (1); + } + + diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index c5c8610..6f09cec 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 140%{?dist} +%define glibcrelease 141%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -530,6 +530,17 @@ Patch393: glibc-rh1704868-4.patch Patch394: glibc-rh1704868-5.patch Patch395: glibc-rh1893662-1.patch Patch396: glibc-rh1893662-2.patch +Patch397: glibc-rh1855790-1.patch +Patch398: glibc-rh1855790-2.patch +Patch399: glibc-rh1855790-3.patch +Patch400: glibc-rh1855790-4.patch +Patch401: glibc-rh1855790-5.patch +Patch402: glibc-rh1855790-6.patch +Patch403: glibc-rh1855790-7.patch +Patch404: glibc-rh1855790-8.patch +Patch405: glibc-rh1855790-9.patch +Patch406: glibc-rh1855790-10.patch +Patch407: glibc-rh1855790-11.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2441,6 +2452,9 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Mon Nov 30 2020 Carlos O'Donell - 2.28-141 +- Update Intel CET support (#1855790) + * Tue Nov 10 2020 Carlos O'Donell - 2.28-140 - Fix calling lazily-bound SVE-using functions on AArch64 (#1893662)