From 144f61240626f7da26462e44979e9498fa735ccb Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Thu, 8 Jun 2023 13:31:34 -0400 Subject: [PATCH] Shadow stack userspace support Downstream only and disabled by default. --- 0001-x86-cet-Don-t-set-CET-active.patch | 71 ++ glibc.spec | 22 +- ...cet-Check-user_shstk-in-proc-cpuinfo.patch | 27 + v2-0002-x86-cet-Update-tst-cet-vfork-1.patch | 103 +++ ...-Don-t-assume-that-SHSTK-implies-IBT.patch | 98 +++ ...eck-legacy-shadow-stack-applications.patch | 209 +++++ ...-CPU_FEATURE_ACTIVE-when-CET-is-disa.patch | 61 ++ ...ests-for-GLIBC_TUNABLES-glibc.cpu.hw.patch | 81 ++ ...-legacy-shadow-stack-code-in-.init_a.patch | 456 ++++++++++ ...-CPU_FEATURE_ACTIVE-in-permissive-mo.patch | 49 ++ v2-0009-x86-Check-PT_GNU_PROPERTY-early.patch | 160 ++++ ...-x86-Modularize-sysdeps-x86-dl-cet.c.patch | 511 +++++++++++ ...xup-asm-unistd.h-and-regenerate-arch.patch | 96 +++ ...with-the-kernel-shadow-stack-interfa.patch | 803 ++++++++++++++++++ ...rovide-_dl_get_dl_main_map-in-libc.a.patch | 59 ++ ...t-Enable-shadow-stack-during-startup.patch | 518 +++++++++++ ...-feature_1-in-TCB-for-active-IBT-and.patch | 89 ++ 17 files changed, 3412 insertions(+), 1 deletion(-) create mode 100644 0001-x86-cet-Don-t-set-CET-active.patch create mode 100644 v2-0001-x86-cet-Check-user_shstk-in-proc-cpuinfo.patch create mode 100644 v2-0002-x86-cet-Update-tst-cet-vfork-1.patch create mode 100644 v2-0003-x86-cet-Don-t-assume-that-SHSTK-implies-IBT.patch create mode 100644 v2-0004-x86-cet-Check-legacy-shadow-stack-applications.patch create mode 100644 v2-0005-x86-cet-Check-CPU_FEATURE_ACTIVE-when-CET-is-disa.patch create mode 100644 v2-0006-x86-cet-Add-tests-for-GLIBC_TUNABLES-glibc.cpu.hw.patch create mode 100644 v2-0007-x86-cet-Check-legacy-shadow-stack-code-in-.init_a.patch create mode 100644 v2-0008-x86-cet-Check-CPU_FEATURE_ACTIVE-in-permissive-mo.patch create mode 100644 v2-0009-x86-Check-PT_GNU_PROPERTY-early.patch create mode 100644 v2-0010-x86-Modularize-sysdeps-x86-dl-cet.c.patch create mode 100644 v2-0011-x86-64-Add-fixup-asm-unistd.h-and-regenerate-arch.patch create mode 100644 v2-0012-x86-cet-Sync-with-the-kernel-shadow-stack-interfa.patch create mode 100644 v2-0013-elf-Always-provide-_dl_get_dl_main_map-in-libc.a.patch create mode 100644 v2-0014-x86-cet-Enable-shadow-stack-during-startup.patch create mode 100644 v2-0015-x86-cet-Check-feature_1-in-TCB-for-active-IBT-and.patch diff --git a/0001-x86-cet-Don-t-set-CET-active.patch b/0001-x86-cet-Don-t-set-CET-active.patch new file mode 100644 index 0000000..d2bdfb4 --- /dev/null +++ b/0001-x86-cet-Don-t-set-CET-active.patch @@ -0,0 +1,71 @@ +From c35bffd52dceed849fa027d607c0671049ee1428 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 12 May 2023 13:52:16 -0700 +Subject: [PATCH] x86/cet: Don't set CET active + +Don't set CET active so that CET is disabled by default. Shadow stack +can be enabled by + +$ export GLIBC_TUNABLES=glibc.cpu.hwcaps=SHSTK + +if shadow stack can be enabled by kernel. +--- + sysdeps/x86/cpu-features.c | 2 +- + sysdeps/x86/cpu-tunables.c | 17 ++++++++++++++++- + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 45bc7fcac3..490a7e38be 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -110,7 +110,7 @@ update_active (struct cpu_features *cpu_features) + if (!CPU_FEATURES_CPU_P (cpu_features, RTM_ALWAYS_ABORT)) + CPU_FEATURE_SET_ACTIVE (cpu_features, RTM); + +-#if CET_ENABLED ++#if CET_ENABLED && 0 + CPU_FEATURE_SET_ACTIVE (cpu_features, IBT); + CPU_FEATURE_SET_ACTIVE (cpu_features, SHSTK); + #endif +diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c +index 0d4f328585..eb5d31821b 100644 +--- a/sysdeps/x86/cpu-tunables.c ++++ b/sysdeps/x86/cpu-tunables.c +@@ -47,6 +47,18 @@ extern __typeof (memcmp) DEFAULT_MEMCMP; + break; \ + } + ++#define CHECK_GLIBC_IFUNC_CPU_BOTH(f, cpu_features, name, \ ++ disable, len) \ ++ _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ ++ if (!DEFAULT_MEMCMP (f, #name, len)) \ ++ { \ ++ if (disable) \ ++ CPU_FEATURE_UNSET (cpu_features, name) \ ++ else \ ++ CPU_FEATURE_SET_ACTIVE (cpu_features, name) \ ++ break; \ ++ } ++ + /* Disable a preferred feature NAME. We don't enable a preferred feature + which isn't available. */ + #define CHECK_GLIBC_IFUNC_PREFERRED_OFF(f, cpu_features, name, len) \ +@@ -162,11 +174,14 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + } + break; + case 5: ++ { ++ CHECK_GLIBC_IFUNC_CPU_BOTH (n, cpu_features, SHSTK, disable, ++ 5); ++ } + if (disable) + { + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, LZCNT, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, MOVBE, 5); +- CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SHSTK, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSSE3, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, XSAVE, 5); + } +-- +2.40.1 + diff --git a/glibc.spec b/glibc.spec index 615a82f..b5da667 100644 --- a/glibc.spec +++ b/glibc.spec @@ -159,7 +159,7 @@ Version: %{glibcversion} # - It allows using the Release number without the %%dist tag in the dependency # generator to make the generated requires interchangeable between Rawhide # and ELN (.elnYY < .fcXX). -%global baserelease 13 +%global baserelease 14 Release: %{baserelease}%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for @@ -232,6 +232,23 @@ Patch17: glibc-cs-path.patch Patch23: glibc-python3.patch Patch24: glibc-disable-werror-tst-realloc.patch +Patch100: v2-0001-x86-cet-Check-user_shstk-in-proc-cpuinfo.patch +Patch101: v2-0002-x86-cet-Update-tst-cet-vfork-1.patch +Patch102: v2-0003-x86-cet-Don-t-assume-that-SHSTK-implies-IBT.patch +Patch103: v2-0004-x86-cet-Check-legacy-shadow-stack-applications.patch +Patch104: v2-0005-x86-cet-Check-CPU_FEATURE_ACTIVE-when-CET-is-disa.patch +Patch105: v2-0006-x86-cet-Add-tests-for-GLIBC_TUNABLES-glibc.cpu.hw.patch +Patch106: v2-0007-x86-cet-Check-legacy-shadow-stack-code-in-.init_a.patch +Patch107: v2-0008-x86-cet-Check-CPU_FEATURE_ACTIVE-in-permissive-mo.patch +Patch108: v2-0009-x86-Check-PT_GNU_PROPERTY-early.patch +Patch109: v2-0010-x86-Modularize-sysdeps-x86-dl-cet.c.patch +Patch110: v2-0011-x86-64-Add-fixup-asm-unistd.h-and-regenerate-arch.patch +Patch111: v2-0012-x86-cet-Sync-with-the-kernel-shadow-stack-interfa.patch +Patch112: v2-0013-elf-Always-provide-_dl_get_dl_main_map-in-libc.a.patch +Patch113: v2-0014-x86-cet-Enable-shadow-stack-during-startup.patch +Patch114: v2-0015-x86-cet-Check-feature_1-in-TCB-for-active-IBT-and.patch +Patch115: 0001-x86-cet-Don-t-set-CET-active.patch + ############################################################################## # Continued list of core "glibc" package information: ############################################################################## @@ -2195,6 +2212,9 @@ update_gconv_modules_cache () %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Thu Jun 08 2023 Siddhesh Poyarekar - 2.37.9000-14 +- Shadow stack userspace support, downstream only and disabled by default. + * Wed Jun 07 2023 Arjun Shankar - 2.37.9000-13 - Auto-sync with upstream branch master, commit 85e6d8b4175fcb195011a0a1bad37d6f3b2355db: diff --git a/v2-0001-x86-cet-Check-user_shstk-in-proc-cpuinfo.patch b/v2-0001-x86-cet-Check-user_shstk-in-proc-cpuinfo.patch new file mode 100644 index 0000000..25aba86 --- /dev/null +++ b/v2-0001-x86-cet-Check-user_shstk-in-proc-cpuinfo.patch @@ -0,0 +1,27 @@ +From c94d3234c48c9e8196144bfc150a8f7eee770986 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 1 Mar 2023 11:26:03 -0800 +Subject: [PATCH v2 01/15] x86/cet: Check user_shstk in /proc/cpuinfo + +Linux kernel reports CPU shadow stack feature in /proc/cpuinfo as +user_shstk, instead of shstk. +--- + sysdeps/x86/tst-cpu-features-cpuinfo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86/tst-cpu-features-cpuinfo.c b/sysdeps/x86/tst-cpu-features-cpuinfo.c +index 18d64375ca..1d6c647b70 100644 +--- a/sysdeps/x86/tst-cpu-features-cpuinfo.c ++++ b/sysdeps/x86/tst-cpu-features-cpuinfo.c +@@ -246,7 +246,7 @@ do_test (int argc, char **argv) + fails += CHECK_PROC (sgx, SGX); + fails += CHECK_PROC (sgx_lc, SGX_LC); + fails += CHECK_PROC (sha_ni, SHA); +- fails += CHECK_PROC (shstk, SHSTK); ++ fails += CHECK_PROC (user_shstk, SHSTK); + fails += CHECK_PROC (smap, SMAP); + fails += CHECK_PROC (smep, SMEP); + fails += CHECK_PROC (smx, SMX); +-- +2.40.1 + diff --git a/v2-0002-x86-cet-Update-tst-cet-vfork-1.patch b/v2-0002-x86-cet-Update-tst-cet-vfork-1.patch new file mode 100644 index 0000000..d2ce592 --- /dev/null +++ b/v2-0002-x86-cet-Update-tst-cet-vfork-1.patch @@ -0,0 +1,103 @@ +From f722c6853035ab390757eb725e0661cf22b9791e Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sun, 16 Jan 2022 12:09:57 -0800 +Subject: [PATCH v2 02/15] x86/cet: Update tst-cet-vfork-1 + +Change tst-cet-vfork-1.c to verify that vfork child return triggers +SIGSEGV due to shadow stack mismatch. +--- + sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c | 43 ++++++++----------- + 1 file changed, 17 insertions(+), 26 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c b/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c +index 9c4b6f4d42..c92ed9e737 100644 +--- a/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c ++++ b/sysdeps/unix/sysv/linux/x86/tst-cet-vfork-1.c +@@ -18,34 +18,26 @@ + . */ + + #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); +- } ++ /* NB: Since child return pops shadow stack which is shared with ++ parent, child must not return after vfork. */ + + if ((p1 = vfork ()) == 0) + { +- pid_t p = getpid (); +- TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))); +- /* Child return should trigger SIGSEGV. */ ++ /* Child return should trigger SIGSEGV due to shadow stack ++ mismatch. */ + return; + } + else if (p1 == -1) +@@ -54,22 +46,22 @@ do_test_1 (void) + _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) + { +- int r; +- if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) +- puts ("waitpid failed"); +- else if (r != 0) +- puts ("pip write in child failed"); ++ puts ("waitpid failed"); ++ _exit (EXIT_FAILURE); ++ } ++ ++ if (!WIFSIGNALED (r) || WTERMSIG (r) != SIGSEGV) ++ { ++ puts ("Child not terminated with SIGSEGV"); ++ _exit (EXIT_FAILURE); + } + + /* Parent exits immediately so that parent returns without triggering +- SIGSEGV when shadow stack isn't in use. */ +- _exit (EXIT_FAILURE); ++ SIGSEGV when shadow stack is in use. */ ++ _exit (EXIT_SUCCESS); + } + + static int +@@ -80,9 +72,8 @@ do_test (void) + return EXIT_UNSUPPORTED; + do_test_1 (); + /* Child exits immediately so that child returns without triggering +- SIGSEGV when shadow stack isn't in use. */ ++ SIGSEGV when shadow stack is in use. */ + _exit (EXIT_FAILURE); + } + +-#define EXPECTED_SIGNAL (_get_ssp () == 0 ? 0 : SIGSEGV) + #include +-- +2.40.1 + diff --git a/v2-0003-x86-cet-Don-t-assume-that-SHSTK-implies-IBT.patch b/v2-0003-x86-cet-Don-t-assume-that-SHSTK-implies-IBT.patch new file mode 100644 index 0000000..67b8c31 --- /dev/null +++ b/v2-0003-x86-cet-Don-t-assume-that-SHSTK-implies-IBT.patch @@ -0,0 +1,98 @@ +From 361cb3ec2ab4322f860d18a3a1d674603fe275c5 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sun, 16 Jan 2022 18:23:58 -0800 +Subject: [PATCH v2 03/15] x86/cet: Don't assume that SHSTK implies IBT + +Since shadow stack (SHSTK) is enabled in the Linux kernel without +enabling indirect branch tracking (IBT), don't assume that SHSTK +implies IBT. Use "CPU_FEATURE_ACTIVE (IBT)" to check if IBT is active +and "CPU_FEATURE_ACTIVE (SHSTK)" to check if SHSTK is active. +--- + sysdeps/x86/Makefile | 1 - + sysdeps/x86/tst-cet-legacy-10.c | 6 +++--- + sysdeps/x86/tst-cet-legacy-8.c | 15 ++++++++------- + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 917c26f116..ea45aad34c 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -165,7 +165,6 @@ 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 + CFLAGS-tst-cet-legacy-10.c += -mshstk + CFLAGS-tst-cet-legacy-10-static.c += -mshstk + +diff --git a/sysdeps/x86/tst-cet-legacy-10.c b/sysdeps/x86/tst-cet-legacy-10.c +index a85cdc3171..ae2c34de3e 100644 +--- a/sysdeps/x86/tst-cet-legacy-10.c ++++ b/sysdeps/x86/tst-cet-legacy-10.c +@@ -21,19 +21,19 @@ + #include + #include + +-/* Check that CPU_FEATURE_ACTIVE on IBT and SHSTK matches _get_ssp. */ ++/* Check that CPU_FEATURE_ACTIVE on SHSTK matches _get_ssp. */ + + static int + do_test (void) + { + if (_get_ssp () != 0) + { +- if (CPU_FEATURE_ACTIVE (IBT) && CPU_FEATURE_ACTIVE (SHSTK)) ++ if (CPU_FEATURE_ACTIVE (SHSTK)) + return EXIT_SUCCESS; + } + else + { +- if (!CPU_FEATURE_ACTIVE (IBT) && !CPU_FEATURE_ACTIVE (SHSTK)) ++ if (!CPU_FEATURE_ACTIVE (SHSTK)) + return EXIT_SUCCESS; + } + +diff --git a/sysdeps/x86/tst-cet-legacy-8.c b/sysdeps/x86/tst-cet-legacy-8.c +index 5d8d9ba7dc..77d77a5408 100644 +--- a/sysdeps/x86/tst-cet-legacy-8.c ++++ b/sysdeps/x86/tst-cet-legacy-8.c +@@ -18,7 +18,7 @@ + + #include + #include +-#include ++#include + #include + #include + #include +@@ -29,11 +29,6 @@ + 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); +@@ -41,8 +36,14 @@ do_test (void) + /* Write RET instruction. */ + *(char *) funcp = 0xc3; + funcp (); ++ ++ /* NB: This test should trigger SIGSEGV when IBT is active. We should ++ reach here if IBT isn't active. */ ++ if (!CPU_FEATURE_ACTIVE (IBT)) ++ return EXIT_UNSUPPORTED; ++ + return EXIT_FAILURE; + } + +-#define EXPECTED_SIGNAL (_get_ssp () == 0 ? 0 : SIGSEGV) ++#define EXPECTED_SIGNAL (CPU_FEATURE_ACTIVE (IBT) ? SIGSEGV : 0) + #include +-- +2.40.1 + diff --git a/v2-0004-x86-cet-Check-legacy-shadow-stack-applications.patch b/v2-0004-x86-cet-Check-legacy-shadow-stack-applications.patch new file mode 100644 index 0000000..77e90c5 --- /dev/null +++ b/v2-0004-x86-cet-Check-legacy-shadow-stack-applications.patch @@ -0,0 +1,209 @@ +From 2db487201909cf8fc1216e0b41e5bdd0d6677460 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 21 Mar 2023 12:53:24 -0700 +Subject: [PATCH v2 04/15] x86/cet: Check legacy shadow stack applications + +Add tests to verify that legacy shadow stack applications run properly +when shadow stack is enabled in Linux kernel. +--- + sysdeps/x86/Makefile | 23 ++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1-extra.S | 35 ++++++++++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1a-static.c | 1 + + sysdeps/x86/tst-shstk-legacy-1a.c | 32 ++++++++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1b-static.c | 1 + + sysdeps/x86/tst-shstk-legacy-1b.c | 38 ++++++++++++++++++++++++ + 6 files changed, 130 insertions(+) + create mode 100644 sysdeps/x86/tst-shstk-legacy-1-extra.S + create mode 100644 sysdeps/x86/tst-shstk-legacy-1a-static.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1a.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1b-static.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1b.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index ea45aad34c..dea14e343c 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -129,6 +129,21 @@ tests += tst-cet-legacy-1 tst-cet-legacy-1a tst-cet-legacy-2 \ + tst-cet-legacy-10 tst-cet-legacy-10-static + tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static + tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd) ++ ++tests += \ ++ tst-shstk-legacy-1a \ ++ tst-shstk-legacy-1a-static \ ++ tst-shstk-legacy-1b \ ++ tst-shstk-legacy-1b-static \ ++# tests ++tests-static += \ ++ tst-shstk-legacy-1a-static \ ++ tst-shstk-legacy-1b-static \ ++# tests-static ++extra-objs += \ ++ tst-shstk-legacy-1-extra.o \ ++# extra-objs ++ + tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ + tst-cet-legacy-5b tst-cet-legacy-6b + modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \ +@@ -168,6 +183,9 @@ CFLAGS-tst-cet-legacy-7.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-10.c += -mshstk + CFLAGS-tst-cet-legacy-10-static.c += -mshstk + ++CFLAGS-tst-shstk-legacy-1a.c += -fcf-protection=none ++CFLAGS-tst-shstk-legacy-1a-static.c += -fcf-protection=none ++ + $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ + $(objpfx)tst-cet-legacy-mod-2.so + $(objpfx)tst-cet-legacy-1a: $(objpfx)tst-cet-legacy-mod-1.so \ +@@ -200,6 +218,11 @@ $(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \ + tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + tst-cet-legacy-9-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK + tst-cet-legacy-9-static-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK ++ ++$(objpfx)tst-shstk-legacy-1a: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1a-static: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1b: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1b-static: $(objpfx)tst-shstk-legacy-1-extra.o + endif + + # Add -fcf-protection to CFLAGS when CET is enabled. +diff --git a/sysdeps/x86/tst-shstk-legacy-1-extra.S b/sysdeps/x86/tst-shstk-legacy-1-extra.S +new file mode 100644 +index 0000000000..f3adb9f639 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1-extra.S +@@ -0,0 +1,35 @@ ++/* Legacy shadow stack code. ++ Copyright (C) 2023 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 ++ . */ ++ ++ .text ++ .globl legacy ++ .type legacy, @function ++legacy: ++ .cfi_startproc ++#ifdef __x86_64__ ++ movq (%rsp), %rax ++ addq $8, %rsp ++ jmp *%rax ++#else ++ movl (%esp), %eax ++ addl $4, %esp ++ jmp *%eax ++#endif ++ .cfi_endproc ++ .size legacy, .-legacy ++ .section .note.GNU-stack,"",@progbits +diff --git a/sysdeps/x86/tst-shstk-legacy-1a-static.c b/sysdeps/x86/tst-shstk-legacy-1a-static.c +new file mode 100644 +index 0000000000..dd549890a0 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1a-static.c +@@ -0,0 +1 @@ ++#include "tst-shstk-legacy-1a.c" +diff --git a/sysdeps/x86/tst-shstk-legacy-1a.c b/sysdeps/x86/tst-shstk-legacy-1a.c +new file mode 100644 +index 0000000000..c6f5810838 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1a.c +@@ -0,0 +1,32 @@ ++/* Check that legacy shadow stack code won't trigger segfault. ++ Copyright (C) 2023 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 ++ ++/* Check that legacy shadow stack code won't trigger segfault. */ ++extern void legacy (void); ++ ++static int ++do_test (void) ++{ ++ legacy (); ++ return EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-shstk-legacy-1b-static.c b/sysdeps/x86/tst-shstk-legacy-1b-static.c +new file mode 100644 +index 0000000000..4945344675 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1b-static.c +@@ -0,0 +1 @@ ++#include "tst-shstk-legacy-1b.c" +diff --git a/sysdeps/x86/tst-shstk-legacy-1b.c b/sysdeps/x86/tst-shstk-legacy-1b.c +new file mode 100644 +index 0000000000..05231e60ae +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1b.c +@@ -0,0 +1,38 @@ ++/* Check that legacy shadow stack code will trigger segfault. ++ Copyright (C) 2023 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 ++ ++/* Check that legacy shadow stack code will trigger segfault. */ ++extern void legacy (void); ++ ++static int ++do_test (void) ++{ ++ if (!CPU_FEATURE_ACTIVE (SHSTK)) ++ return EXIT_UNSUPPORTED; ++ ++ legacy (); ++ return EXIT_FAILURE; ++} ++ ++#define EXPECTED_SIGNAL (CPU_FEATURE_ACTIVE (SHSTK) ? SIGSEGV : 0) ++#include +-- +2.40.1 + diff --git a/v2-0005-x86-cet-Check-CPU_FEATURE_ACTIVE-when-CET-is-disa.patch b/v2-0005-x86-cet-Check-CPU_FEATURE_ACTIVE-when-CET-is-disa.patch new file mode 100644 index 0000000..1ae6e2c --- /dev/null +++ b/v2-0005-x86-cet-Check-CPU_FEATURE_ACTIVE-when-CET-is-disa.patch @@ -0,0 +1,61 @@ +From 13543173f98ca8f01311fa6a2bca409128561d18 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 10 Mar 2023 13:18:10 -0800 +Subject: [PATCH v2 05/15] x86/cet: Check CPU_FEATURE_ACTIVE when CET is + disabled + +Verify that CPU_FEATURE_ACTIVE (SHSTK) works properly when CET is +disabled. +--- + sysdeps/x86/Makefile | 8 ++++++-- + sysdeps/x86/tst-cet-legacy-10a-static.c | 2 ++ + sysdeps/x86/tst-cet-legacy-10a.c | 2 ++ + 3 files changed, 10 insertions(+), 2 deletions(-) + create mode 100644 sysdeps/x86/tst-cet-legacy-10a-static.c + create mode 100644 sysdeps/x86/tst-cet-legacy-10a.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index dea14e343c..580c3ecdc5 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -126,8 +126,10 @@ tests += tst-cet-legacy-1 tst-cet-legacy-1a 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-7 \ + tst-cet-legacy-8 tst-cet-legacy-9 tst-cet-legacy-9-static \ +- tst-cet-legacy-10 tst-cet-legacy-10-static +-tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static ++ tst-cet-legacy-10 tst-cet-legacy-10-static \ ++ tst-cet-legacy-10a tst-cet-legacy-10a-static ++tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static \ ++ tst-cet-legacy-10a-static + tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd) + + tests += \ +@@ -182,6 +184,8 @@ CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection + CFLAGS-tst-cet-legacy-7.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-10.c += -mshstk + CFLAGS-tst-cet-legacy-10-static.c += -mshstk ++CFLAGS-tst-cet-legacy-10a.c += -fcf-protection=none ++CFLAGS-tst-cet-legacy-10a-static.c += -fcf-protection=none + + CFLAGS-tst-shstk-legacy-1a.c += -fcf-protection=none + CFLAGS-tst-shstk-legacy-1a-static.c += -fcf-protection=none +diff --git a/sysdeps/x86/tst-cet-legacy-10a-static.c b/sysdeps/x86/tst-cet-legacy-10a-static.c +new file mode 100644 +index 0000000000..05073a5d1e +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-10a-static.c +@@ -0,0 +1,2 @@ ++#pragma GCC target ("shstk") ++#include "tst-cet-legacy-10.c" +diff --git a/sysdeps/x86/tst-cet-legacy-10a.c b/sysdeps/x86/tst-cet-legacy-10a.c +new file mode 100644 +index 0000000000..05073a5d1e +--- /dev/null ++++ b/sysdeps/x86/tst-cet-legacy-10a.c +@@ -0,0 +1,2 @@ ++#pragma GCC target ("shstk") ++#include "tst-cet-legacy-10.c" +-- +2.40.1 + diff --git a/v2-0006-x86-cet-Add-tests-for-GLIBC_TUNABLES-glibc.cpu.hw.patch b/v2-0006-x86-cet-Add-tests-for-GLIBC_TUNABLES-glibc.cpu.hw.patch new file mode 100644 index 0000000..76f5e00 --- /dev/null +++ b/v2-0006-x86-cet-Add-tests-for-GLIBC_TUNABLES-glibc.cpu.hw.patch @@ -0,0 +1,81 @@ +From 7a97a9ab63a37ae1191e514258e4f6fefdc2e41b Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 17 Mar 2023 16:21:49 -0700 +Subject: [PATCH v2 06/15] x86/cet: Add tests for + GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK + +Verify that GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK turns off shadow +stack properly. +--- + sysdeps/x86/Makefile | 7 +++++++ + sysdeps/x86/tst-shstk-legacy-1c-static.c | 1 + + sysdeps/x86/tst-shstk-legacy-1c.c | 20 ++++++++++++++++++++ + 3 files changed, 28 insertions(+) + create mode 100644 sysdeps/x86/tst-shstk-legacy-1c-static.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1c.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 580c3ecdc5..5f1414fba3 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -137,10 +137,13 @@ tests += \ + tst-shstk-legacy-1a-static \ + tst-shstk-legacy-1b \ + tst-shstk-legacy-1b-static \ ++ tst-shstk-legacy-1c \ ++ tst-shstk-legacy-1c-static \ + # tests + tests-static += \ + tst-shstk-legacy-1a-static \ + tst-shstk-legacy-1b-static \ ++ tst-shstk-legacy-1c-static \ + # tests-static + extra-objs += \ + tst-shstk-legacy-1-extra.o \ +@@ -227,6 +230,10 @@ $(objpfx)tst-shstk-legacy-1a: $(objpfx)tst-shstk-legacy-1-extra.o + $(objpfx)tst-shstk-legacy-1a-static: $(objpfx)tst-shstk-legacy-1-extra.o + $(objpfx)tst-shstk-legacy-1b: $(objpfx)tst-shstk-legacy-1-extra.o + $(objpfx)tst-shstk-legacy-1b-static: $(objpfx)tst-shstk-legacy-1-extra.o ++tst-shstk-legacy-1c-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK ++tst-shstk-legacy-1c-static-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK ++$(objpfx)tst-shstk-legacy-1c: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1c-static: $(objpfx)tst-shstk-legacy-1-extra.o + endif + + # Add -fcf-protection to CFLAGS when CET is enabled. +diff --git a/sysdeps/x86/tst-shstk-legacy-1c-static.c b/sysdeps/x86/tst-shstk-legacy-1c-static.c +new file mode 100644 +index 0000000000..91ea346aaf +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1c-static.c +@@ -0,0 +1 @@ ++#include "tst-shstk-legacy-1c.c" +diff --git a/sysdeps/x86/tst-shstk-legacy-1c.c b/sysdeps/x86/tst-shstk-legacy-1c.c +new file mode 100644 +index 0000000000..eb218c6c70 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1c.c +@@ -0,0 +1,20 @@ ++/* Check that legacy shadow stack code won't trigger segfault with ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK ++ Copyright (C) 2023 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 "tst-shstk-legacy-1a.c" +-- +2.40.1 + diff --git a/v2-0007-x86-cet-Check-legacy-shadow-stack-code-in-.init_a.patch b/v2-0007-x86-cet-Check-legacy-shadow-stack-code-in-.init_a.patch new file mode 100644 index 0000000..fb73597 --- /dev/null +++ b/v2-0007-x86-cet-Check-legacy-shadow-stack-code-in-.init_a.patch @@ -0,0 +1,456 @@ +From d3bf3cba97111334082b817e59ff2840dbc98afa Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 22 Mar 2023 13:34:55 -0700 +Subject: [PATCH v2 07/15] x86/cet: Check legacy shadow stack code in + .init_array section + +Verify that legacy shadow stack code in .init_array section in application +and shared library, which are marked as shadow stack enabled, will trigger +segfault. +--- + sysdeps/x86/Makefile | 36 +++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1d-static.c | 1 + + sysdeps/x86/tst-shstk-legacy-1d.c | 47 ++++++++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1e-static.c | 1 + + sysdeps/x86/tst-shstk-legacy-1e-static.sh | 32 ++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1e.c | 53 +++++++++++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1e.sh | 34 +++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1f.c | 29 +++++++++++++ + sysdeps/x86/tst-shstk-legacy-1g.c | 35 +++++++++++++++ + sysdeps/x86/tst-shstk-legacy-1g.sh | 34 +++++++++++++++ + sysdeps/x86/tst-shstk-legacy-mod-1.c | 28 ++++++++++++ + 11 files changed, 330 insertions(+) + create mode 100644 sysdeps/x86/tst-shstk-legacy-1d-static.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1d.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1e-static.c + create mode 100755 sysdeps/x86/tst-shstk-legacy-1e-static.sh + create mode 100644 sysdeps/x86/tst-shstk-legacy-1e.c + create mode 100755 sysdeps/x86/tst-shstk-legacy-1e.sh + create mode 100644 sysdeps/x86/tst-shstk-legacy-1f.c + create mode 100644 sysdeps/x86/tst-shstk-legacy-1g.c + create mode 100755 sysdeps/x86/tst-shstk-legacy-1g.sh + create mode 100644 sysdeps/x86/tst-shstk-legacy-mod-1.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 5f1414fba3..b8b98177e0 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -139,11 +139,22 @@ tests += \ + tst-shstk-legacy-1b-static \ + tst-shstk-legacy-1c \ + tst-shstk-legacy-1c-static \ ++ tst-shstk-legacy-1d \ ++ tst-shstk-legacy-1d-static \ ++ tst-shstk-legacy-1e \ ++ tst-shstk-legacy-1e-static \ ++ tst-shstk-legacy-1f \ ++ tst-shstk-legacy-1g \ + # tests ++modules-names += \ ++ tst-shstk-legacy-mod-1 \ ++# modules-names + tests-static += \ + tst-shstk-legacy-1a-static \ + tst-shstk-legacy-1b-static \ + tst-shstk-legacy-1c-static \ ++ tst-shstk-legacy-1d-static \ ++ tst-shstk-legacy-1e-static \ + # tests-static + extra-objs += \ + tst-shstk-legacy-1-extra.o \ +@@ -192,6 +203,9 @@ CFLAGS-tst-cet-legacy-10a-static.c += -fcf-protection=none + + CFLAGS-tst-shstk-legacy-1a.c += -fcf-protection=none + CFLAGS-tst-shstk-legacy-1a-static.c += -fcf-protection=none ++CFLAGS-tst-shstk-legacy-1d.c += -fcf-protection=none ++CFLAGS-tst-shstk-legacy-1d-static.c += -fcf-protection=none ++CFLAGS-tst-shstk-legacy-1f.c += -fcf-protection=none + + $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ + $(objpfx)tst-cet-legacy-mod-2.so +@@ -234,6 +248,28 @@ tst-shstk-legacy-1c-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK + tst-shstk-legacy-1c-static-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK + $(objpfx)tst-shstk-legacy-1c: $(objpfx)tst-shstk-legacy-1-extra.o + $(objpfx)tst-shstk-legacy-1c-static: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1d: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1d-static: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1e: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1e-static: $(objpfx)tst-shstk-legacy-1-extra.o ++$(objpfx)tst-shstk-legacy-1e.out: \ ++ $(..)/sysdeps/x86/tst-shstk-legacy-1e.sh $(objpfx)tst-shstk-legacy-1e ++ $(SHELL) $< $(common-objpfx) '$(test-program-prefix)' 2> $@; \ ++ $(evaluate-test) ++$(objpfx)tst-shstk-legacy-1e-static.out: \ ++ $(..)/sysdeps/x86/tst-shstk-legacy-1e-static.sh \ ++ $(objpfx)tst-shstk-legacy-1e-static ++ $(SHELL) $< $(common-objpfx) 2> $@; \ ++ $(evaluate-test) ++$(objpfx)tst-shstk-legacy-1f: $(objpfx)tst-shstk-legacy-mod-1.so ++$(objpfx)tst-shstk-legacy-mod-1.so: \ ++ $(objpfx)tst-shstk-legacy-mod-1.os \ ++ $(objpfx)tst-shstk-legacy-1-extra.os ++$(objpfx)tst-shstk-legacy-1g: $(objpfx)tst-shstk-legacy-mod-1.so ++$(objpfx)tst-shstk-legacy-1g.out: \ ++ $(..)/sysdeps/x86/tst-shstk-legacy-1g.sh $(objpfx)tst-shstk-legacy-1g ++ $(SHELL) $< $(common-objpfx) '$(test-program-prefix)' 2> $@; \ ++ $(evaluate-test) + endif + + # Add -fcf-protection to CFLAGS when CET is enabled. +diff --git a/sysdeps/x86/tst-shstk-legacy-1d-static.c b/sysdeps/x86/tst-shstk-legacy-1d-static.c +new file mode 100644 +index 0000000000..dca27a5482 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1d-static.c +@@ -0,0 +1 @@ ++#include "tst-shstk-legacy-1d.c" +diff --git a/sysdeps/x86/tst-shstk-legacy-1d.c b/sysdeps/x86/tst-shstk-legacy-1d.c +new file mode 100644 +index 0000000000..465cfab1db +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1d.c +@@ -0,0 +1,47 @@ ++/* Check that legacy shadow stack code in init_array won't trigger ++ segfault. ++ Copyright (C) 2023 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 ++ ++/* Check that legacy shadow stack code in init_array won't trigger ++ segfault. */ ++extern void legacy (void); ++int done; ++ ++void ++legacy_1 (void) ++{ ++ legacy (); ++ done = 1; ++} ++ ++void (*init_array []) (void) ++ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = ++{ ++ &legacy_1 ++}; ++ ++static int ++do_test (void) ++{ ++ return EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-shstk-legacy-1e-static.c b/sysdeps/x86/tst-shstk-legacy-1e-static.c +new file mode 100644 +index 0000000000..cb6ce0de00 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1e-static.c +@@ -0,0 +1 @@ ++#include "tst-shstk-legacy-1e.c" +diff --git a/sysdeps/x86/tst-shstk-legacy-1e-static.sh b/sysdeps/x86/tst-shstk-legacy-1e-static.sh +new file mode 100755 +index 0000000000..e943aec70e +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1e-static.sh +@@ -0,0 +1,32 @@ ++#!/bin/sh ++# Check that legacy shadow stack code in init_array will trigger ++# segfault. ++# Copyright (C) 2023 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 ++# . ++ ++common_objpfx=$1; shift ++ ++${common_objpfx}elf/tst-shstk-legacy-1e-static ++# The exit status should only be unsupported (77) or segfault (139). ++status=$? ++if test $status -eq 77; then ++ exit 77 ++elif test $status == 139; then ++ exit 0 ++else ++ exit 1 ++fi +diff --git a/sysdeps/x86/tst-shstk-legacy-1e.c b/sysdeps/x86/tst-shstk-legacy-1e.c +new file mode 100644 +index 0000000000..e78a4b776e +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1e.c +@@ -0,0 +1,53 @@ ++/* Check that legacy shadow stack code in init_array will trigger ++ segfault. ++ Copyright (C) 2023 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 ++ ++/* Check that legacy shadow stack code in init_array will trigger ++ segfault. */ ++extern void legacy (void); ++int done; ++ ++void ++legacy_1 (void) ++{ ++ legacy (); ++ done = 1; ++} ++ ++void (*init_array []) (void) ++ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = ++{ ++ &legacy_1 ++}; ++ ++static int ++do_test (void) ++{ ++ if (!CPU_FEATURE_ACTIVE (SHSTK)) ++ return EXIT_UNSUPPORTED; ++ ++ return EXIT_FAILURE; ++} ++ ++#define EXPECTED_SIGNAL (CPU_FEATURE_ACTIVE (SHSTK) ? SIGSEGV : 0) ++#include +diff --git a/sysdeps/x86/tst-shstk-legacy-1e.sh b/sysdeps/x86/tst-shstk-legacy-1e.sh +new file mode 100755 +index 0000000000..b0467aa899 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1e.sh +@@ -0,0 +1,34 @@ ++#!/bin/sh ++# Check that legacy shadow stack code in init_array will trigger ++# segfault. ++# Copyright (C) 2023 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 ++# . ++ ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++${test_program_prefix} \ ++ ${common_objpfx}elf/tst-shstk-legacy-1e ++# The exit status should only be unsupported (77) or segfault (139). ++status=$? ++if test $status -eq 77; then ++ exit 77 ++elif test $status == 139; then ++ exit 0 ++else ++ exit 1 ++fi +diff --git a/sysdeps/x86/tst-shstk-legacy-1f.c b/sysdeps/x86/tst-shstk-legacy-1f.c +new file mode 100644 +index 0000000000..27e01a229e +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1f.c +@@ -0,0 +1,29 @@ ++/* Check that legacy shadow stack code in init_array won't trigger ++ segfault. ++ Copyright (C) 2023 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 ++ ++static int ++do_test (void) ++{ ++ return EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86/tst-shstk-legacy-1g.c b/sysdeps/x86/tst-shstk-legacy-1g.c +new file mode 100644 +index 0000000000..a1f3d242e9 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1g.c +@@ -0,0 +1,35 @@ ++/* Check that legacy shadow stack code in init_array will trigger ++ segfault. ++ Copyright (C) 2023 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 ++ ++static int ++do_test (void) ++{ ++ if (!CPU_FEATURE_ACTIVE (SHSTK)) ++ return EXIT_UNSUPPORTED; ++ ++ return EXIT_FAILURE; ++} ++ ++#define EXPECTED_SIGNAL (CPU_FEATURE_ACTIVE (SHSTK) ? SIGSEGV : 0) ++#include +diff --git a/sysdeps/x86/tst-shstk-legacy-1g.sh b/sysdeps/x86/tst-shstk-legacy-1g.sh +new file mode 100755 +index 0000000000..c112bf6d8d +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-1g.sh +@@ -0,0 +1,34 @@ ++#!/bin/sh ++# Check that legacy shadow stack code in init_array will trigger ++# segfault. ++# Copyright (C) 2023 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 ++# . ++ ++common_objpfx=$1; shift ++test_program_prefix=$1; shift ++ ++${test_program_prefix} \ ++ ${common_objpfx}elf/tst-shstk-legacy-1g ++# The exit status should only be unsupported (77) or segfault (139). ++status=$? ++if test $status -eq 77; then ++ exit 77 ++elif test $status == 139; then ++ exit 0 ++else ++ exit 1 ++fi +diff --git a/sysdeps/x86/tst-shstk-legacy-mod-1.c b/sysdeps/x86/tst-shstk-legacy-mod-1.c +new file mode 100644 +index 0000000000..b75b5484d9 +--- /dev/null ++++ b/sysdeps/x86/tst-shstk-legacy-mod-1.c +@@ -0,0 +1,28 @@ ++/* Check legacy shadow stack code in init_array. ++ Copyright (C) 2023 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 ++ ++/* Check legacy shadow stack code in init_array. */ ++extern void legacy (void) __attribute__ ((visibility ("hidden"))); ++ ++void (*init_array []) (void) ++ __attribute__ ((section (".init_array"), aligned (sizeof (void *)))) = ++{ ++ &legacy ++}; +-- +2.40.1 + diff --git a/v2-0008-x86-cet-Check-CPU_FEATURE_ACTIVE-in-permissive-mo.patch b/v2-0008-x86-cet-Check-CPU_FEATURE_ACTIVE-in-permissive-mo.patch new file mode 100644 index 0000000..1c26421 --- /dev/null +++ b/v2-0008-x86-cet-Check-CPU_FEATURE_ACTIVE-in-permissive-mo.patch @@ -0,0 +1,49 @@ +From 8230fefd2495d1fb7fa72c680dc10ae4d10fde61 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 28 Mar 2023 13:52:36 -0700 +Subject: [PATCH v2 08/15] x86/cet: Check CPU_FEATURE_ACTIVE in permissive mode + +Verify that CPU_FEATURE_ACTIVE works properly in permissive mode. +--- + sysdeps/x86/Makefile | 1 + + sysdeps/x86/tst-cet-legacy-4.c | 5 +++++ + 2 files changed, 6 insertions(+) + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index b8b98177e0..6ceefe16c7 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -174,6 +174,7 @@ CFLAGS-tst-cet-legacy-mod-1.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-mod-2.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-3.c += -fcf-protection=none + CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch ++CPPFLAGS-tst-cet-legacy-4a.c += -DCET_IS_PERMISSIVE=1 + 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 +diff --git a/sysdeps/x86/tst-cet-legacy-4.c b/sysdeps/x86/tst-cet-legacy-4.c +index d75fb0e61c..c098120253 100644 +--- a/sysdeps/x86/tst-cet-legacy-4.c ++++ b/sysdeps/x86/tst-cet-legacy-4.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include + +@@ -40,6 +41,10 @@ do_test (void) + return 0; + } + ++#ifdef CET_IS_PERMISSIVE ++ TEST_VERIFY (!CPU_FEATURE_ACTIVE (IBT) && !CPU_FEATURE_ACTIVE (SHSTK)); ++#endif ++ + fp = dlsym (h, "test"); + if (fp == NULL) + FAIL_EXIT1 ("cannot get symbol 'test': %s\n", dlerror ()); +-- +2.40.1 + diff --git a/v2-0009-x86-Check-PT_GNU_PROPERTY-early.patch b/v2-0009-x86-Check-PT_GNU_PROPERTY-early.patch new file mode 100644 index 0000000..01ec3c0 --- /dev/null +++ b/v2-0009-x86-Check-PT_GNU_PROPERTY-early.patch @@ -0,0 +1,160 @@ +From 4323e979bd1745e10ae29667c290bff7f74d38e4 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 13 Jan 2022 14:45:46 -0800 +Subject: [PATCH v2 09/15] x86: Check PT_GNU_PROPERTY early + +The PT_GNU_PROPERTY segment is scanned before PT_NOTE. For binaries +with the PT_GNU_PROPERTY segment, we can check it to avoid scan of +the PT_NOTE segment. +--- + sysdeps/x86/dl-prop.h | 120 ++++++++++++++++++++++++++++-------------- + 1 file changed, 80 insertions(+), 40 deletions(-) + +diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h +index 87702df040..ca07b83701 100644 +--- a/sysdeps/x86/dl-prop.h ++++ b/sysdeps/x86/dl-prop.h +@@ -81,6 +81,60 @@ _dl_open_check (struct link_map *m) + #endif + } + ++/* Check the GNU property and return its value. It returns: ++ -1: Skip this note. ++ 0: Stop checking. ++ 1: Continue to check. ++ */ ++static inline int ++_dl_check_gnu_property (unsigned int type, unsigned int datasz, ++ void *ptr, unsigned int *feature_1_and, ++ unsigned int *needed_1, ++ unsigned int *isa_1_needed) ++{ ++ if (type == GNU_PROPERTY_X86_FEATURE_1_AND ++ || type == GNU_PROPERTY_X86_ISA_1_NEEDED ++ || type == GNU_PROPERTY_1_NEEDED) ++ { ++ /* The sizes of types which we are searching for are ++ 4 bytes. There is no point to continue if this ++ note is ill-formed. */ ++ if (datasz != 4) ++ return -1; ++ ++ /* NB: Stop the scan only after seeing all types which ++ we are searching for. */ ++ _Static_assert (((GNU_PROPERTY_X86_ISA_1_NEEDED ++ > GNU_PROPERTY_X86_FEATURE_1_AND) ++ && (GNU_PROPERTY_X86_FEATURE_1_AND ++ > GNU_PROPERTY_1_NEEDED)), ++ "GNU_PROPERTY_X86_ISA_1_NEEDED > " ++ "GNU_PROPERTY_X86_FEATURE_1_AND && " ++ "GNU_PROPERTY_X86_FEATURE_1_AND > " ++ "GNU_PROPERTY_1_NEEDED"); ++ if (type == GNU_PROPERTY_X86_FEATURE_1_AND) ++ *feature_1_and = *(unsigned int *) ptr; ++ else if (type == GNU_PROPERTY_1_NEEDED) ++ *needed_1 = *(unsigned int *) ptr; ++ else ++ { ++ *isa_1_needed = *(unsigned int *) ptr; ++ ++ /* Keep searching for the next GNU property note ++ generated by the older linker. */ ++ return 0; ++ } ++ } ++ else if (type > GNU_PROPERTY_X86_ISA_1_NEEDED) ++ { ++ /* Stop the scan since property type is in ascending ++ order. */ ++ return 0; ++ } ++ ++ return 1; ++} ++ + static inline void __attribute__ ((unused)) + _dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note, + const ElfW(Addr) size, const ElfW(Addr) align) +@@ -141,45 +195,14 @@ _dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note, + + last_type = type; + +- if (type == GNU_PROPERTY_X86_FEATURE_1_AND +- || type == GNU_PROPERTY_X86_ISA_1_NEEDED +- || type == GNU_PROPERTY_1_NEEDED) +- { +- /* The sizes of types which we are searching for are +- 4 bytes. There is no point to continue if this +- note is ill-formed. */ +- if (datasz != 4) +- return; +- +- /* NB: Stop the scan only after seeing all types which +- we are searching for. */ +- _Static_assert (((GNU_PROPERTY_X86_ISA_1_NEEDED +- > GNU_PROPERTY_X86_FEATURE_1_AND) +- && (GNU_PROPERTY_X86_FEATURE_1_AND +- > GNU_PROPERTY_1_NEEDED)), +- "GNU_PROPERTY_X86_ISA_1_NEEDED > " +- "GNU_PROPERTY_X86_FEATURE_1_AND && " +- "GNU_PROPERTY_X86_FEATURE_1_AND > " +- "GNU_PROPERTY_1_NEEDED"); +- if (type == GNU_PROPERTY_X86_FEATURE_1_AND) +- feature_1_and = *(unsigned int *) ptr; +- else if (type == GNU_PROPERTY_1_NEEDED) +- needed_1 = *(unsigned int *) ptr; +- else +- { +- isa_1_needed = *(unsigned int *) ptr; +- +- /* Keep searching for the next GNU property note +- generated by the older linker. */ +- break; +- } +- } +- else if (type > GNU_PROPERTY_X86_ISA_1_NEEDED) +- { +- /* Stop the scan since property type is in ascending +- order. */ +- break; +- } ++ int result = _dl_check_gnu_property (type, datasz, ptr, ++ &feature_1_and, ++ &needed_1, ++ &isa_1_needed); ++ if (result == -1) ++ return; /* Skip this note. */ ++ else if (result == 0) ++ break; /* Stop checking. */ + + /* Check the next property item. */ + ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr))); +@@ -217,7 +240,24 @@ static inline int __attribute__ ((always_inline)) + _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, + uint32_t datasz, void *data) + { +- return 0; ++ /* This is called on each GNU property. */ ++ unsigned int needed_1 = 0; ++ unsigned int feature_1_and = 0; ++ unsigned int isa_1_needed = 0; ++ int result = _dl_check_gnu_property (type, datasz, data, ++ &feature_1_and, &needed_1, ++ &isa_1_needed); ++ if (needed_1 != 0) ++ l->l_1_needed = needed_1; ++ if (isa_1_needed != 0) ++ l->l_x86_isa_1_needed = isa_1_needed; ++ if (feature_1_and != 0) ++ l->l_x86_feature_1_and = feature_1_and; ++ if ((needed_1 | isa_1_needed | feature_1_and) != 0) ++ l->l_property = lc_property_valid; ++ else if (l->l_property == lc_property_unknown) ++ l->l_property = lc_property_none; ++ return result <= 0 ? 0 : result; + } + + #endif /* _DL_PROP_H */ +-- +2.40.1 + diff --git a/v2-0010-x86-Modularize-sysdeps-x86-dl-cet.c.patch b/v2-0010-x86-Modularize-sysdeps-x86-dl-cet.c.patch new file mode 100644 index 0000000..ca881d2 --- /dev/null +++ b/v2-0010-x86-Modularize-sysdeps-x86-dl-cet.c.patch @@ -0,0 +1,511 @@ +From 8431e78b2df0ee194ac0bbd5a5136e89765444c4 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 24 Mar 2023 13:20:06 -0700 +Subject: [PATCH v2 10/15] x86: Modularize sysdeps/x86/dl-cet.c + +Improve readability and make maintenance easier for dl-feature.c by +modularizing sysdeps/x86/dl-cet.c: +1. Support processors with: + a. Only IBT. Or + b. Only SHSTK. Or + c. Both IBT and SHSTK. +2. Lock CET features only if IBT or SHSTK are enabled and are not +enabled permissively. +--- + sysdeps/x86/dl-cet.c | 456 ++++++++++++++++++++++++++----------------- + 1 file changed, 280 insertions(+), 176 deletions(-) + +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 60ea1cb558..67c51ee8c2 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -32,206 +32,310 @@ + # error GNU_PROPERTY_X86_FEATURE_1_SHSTK != X86_FEATURE_1_SHSTK + #endif + +-/* Check if object M is compatible with CET. */ ++struct dl_cet_info ++{ ++ const char *program; ++ ++ /* Check how IBT and SHSTK should be enabled. */ ++ enum dl_x86_cet_control enable_ibt_type; ++ enum dl_x86_cet_control enable_shstk_type; ++ ++ /* If IBT and SHSTK were previously enabled. */ ++ unsigned int feature_1_enabled; ++ ++ /* If IBT and SHSTK should be enabled. */ ++ unsigned int enable_feature_1; ++ ++ /* If there are any legacy shared object. */ ++ unsigned int feature_1_legacy; ++ ++ /* Which shared object is the first legacy shared object. */ ++ unsigned int feature_1_legacy_ibt; ++ unsigned int feature_1_legacy_shstk; ++}; ++ ++/* Check if the object M and its dependencies are legacy object. */ + + static void +-dl_cet_check (struct link_map *m, const char *program) ++dl_check_legacy_object (struct link_map *m, ++ struct dl_cet_info *info) + { +- /* Check how IBT should be enabled. */ +- enum dl_x86_cet_control enable_ibt_type +- = GL(dl_x86_feature_control).ibt; +- /* Check how SHSTK should be enabled. */ +- 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) ++ unsigned int i; ++ struct link_map *l = NULL; ++ ++ i = m->l_searchlist.r_nlist; ++ while (i-- > 0) + { +- THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); +- return; +- } ++ /* Check each shared object to see if IBT and SHSTK are enabled. */ ++ l = m->l_initfini[i]; + +- /* Check if IBT is enabled by kernel. */ +- bool ibt_enabled +- = (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) & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; ++ if (l->l_init_called) ++ continue; + +- 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 +- && enable_ibt_type != cet_always_off); +- bool enable_shstk = (shstk_enabled +- && enable_shstk_type != cet_always_off); +- if (program) ++#ifdef SHARED ++ /* Skip check for ld.so since it has the features enabled. The ++ features will be disabled later if they are not enabled in ++ executable. */ ++ if (l == &GL(dl_rtld_map) ++ || l->l_real == &GL(dl_rtld_map) ++ || (info->program != NULL && l == m)) ++ continue; ++#endif ++ ++ /* IBT and SHSTK set only if enabled in executable and all DSOs. ++ NB: cet_always_on is handled outside of the loop. */ ++ info->enable_feature_1 &= ((l->l_x86_feature_1_and ++ & (GNU_PROPERTY_X86_FEATURE_1_IBT ++ | GNU_PROPERTY_X86_FEATURE_1_SHSTK)) ++ | ~(GNU_PROPERTY_X86_FEATURE_1_IBT ++ | GNU_PROPERTY_X86_FEATURE_1_SHSTK)); ++ if ((info->feature_1_legacy ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0 ++ && ((info->enable_feature_1 ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) ++ != (info->feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_IBT))) + { +- /* Enable IBT and SHSTK only if they are enabled in executable. +- NB: IBT and SHSTK may be disabled by environment variable: +- +- GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK +- */ +- enable_ibt &= (CPU_FEATURE_USABLE (IBT) +- && (enable_ibt_type == cet_always_on +- || (m->l_x86_feature_1_and +- & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0)); +- enable_shstk &= (CPU_FEATURE_USABLE (SHSTK) +- && (enable_shstk_type == cet_always_on +- || (m->l_x86_feature_1_and +- & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0)); ++ info->feature_1_legacy_ibt = i; ++ info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_IBT; + } + +- /* ld.so is CET-enabled by kernel. But shared objects may not +- support IBT nor SHSTK. */ +- if (enable_ibt || enable_shstk) +- { +- unsigned int i; ++ if ((info->feature_1_legacy ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0 ++ && ((info->enable_feature_1 ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) ++ != (info->feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK))) ++ { ++ info->feature_1_legacy_shstk = i; ++ info->feature_1_legacy |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ } ++ } + +- 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]; ++ /* Handle cet_always_on. */ ++ if ((info->feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0 ++ && info->enable_ibt_type == cet_always_on) ++ { ++ info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_IBT; ++ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT; ++ } + +- if (l->l_init_called) +- continue; ++ if ((info->feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0 ++ && info->enable_shstk_type == cet_always_on) ++ { ++ info->feature_1_legacy &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ } ++} + + #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; ++/* Enable IBT and SHSTK only if they are enabled in executable. Set ++ feature bits properly at the start of the program. */ ++ ++static void ++dl_cet_check_startup (struct link_map *m, struct dl_cet_info *info) ++{ ++ /* NB: IBT and SHSTK may be disabled by environment variable: ++ ++ GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK. ++ */ ++ if (CPU_FEATURE_USABLE (IBT)) ++ { ++ if (info->enable_ibt_type == cet_always_on) ++ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT; ++ else ++ info->enable_feature_1 &= ((m->l_x86_feature_1_and ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) ++ | ~GNU_PROPERTY_X86_FEATURE_1_IBT); ++ } ++ else ++ info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_IBT; ++ ++ if (CPU_FEATURE_USABLE (SHSTK)) ++ { ++ if (info->enable_shstk_type == cet_always_on) ++ info->enable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ else ++ info->enable_feature_1 &= ((m->l_x86_feature_1_and ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) ++ | ~GNU_PROPERTY_X86_FEATURE_1_SHSTK); ++ } ++ else ++ info->enable_feature_1 &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ ++ if (info->enable_feature_1 != 0) ++ dl_check_legacy_object (m, info); ++ ++ unsigned int disable_feature_1 ++ = info->enable_feature_1 ^ info->feature_1_enabled; ++ if (disable_feature_1 != 0) ++ { ++ /* Disable features in the kernel because of legacy objects or ++ cet_always_off. */ ++ if (dl_cet_disable_cet (disable_feature_1) != 0) ++ _dl_fatal_printf ("%s: can't disable x86 Features\n", ++ info->program); ++ ++ /* Clear the disabled bits. Sync dl_x86_feature_1 and ++ info->feature_1_enabled with info->enable_feature_1. */ ++ info->feature_1_enabled = info->enable_feature_1; ++ GL(dl_x86_feature_1) = info->enable_feature_1; ++ } ++ ++ if (HAS_CPU_FEATURE (IBT) || HAS_CPU_FEATURE (SHSTK)) ++ { ++ /* Lock CET features only if IBT or SHSTK are enabled and are not ++ enabled permissively. */ ++ unsigned int feature_1_lock = 0; ++ ++ if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_IBT) ++ != 0) ++ && info->enable_ibt_type != cet_permissive) ++ feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_IBT; ++ ++ if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_SHSTK) ++ != 0) ++ && info->enable_shstk_type != cet_permissive) ++ feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ ++ if (feature_1_lock != 0 ++ && dl_cet_lock_cet () != 0) ++ _dl_fatal_printf ("%s: can't lock CET\n", info->program); ++ } ++ ++ THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); ++} + #endif + +- /* 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_x86_feature_1_and +- & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0); +- if (!found_ibt_legacy && enable_ibt != ibt_enabled) +- { +- 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_x86_feature_1_and +- & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0); +- if (enable_shstk != shstk_enabled) +- { +- found_shstk_legacy = true; +- shstk_legacy = i; +- } +- } +- } ++/* Check feature bits when dlopening the shared object M. */ ++ ++static void ++dl_cet_check_dlopen (struct link_map *m, struct dl_cet_info *info) ++{ ++ /* Check if there are any legacy objects loaded. */ ++ if (info->enable_feature_1 != 0) ++ { ++ dl_check_legacy_object (m, info); + +- bool cet_feature_changed = false; ++ /* Skip if there are no legacy shared objects loaded. */ ++ if (info->feature_1_legacy == 0) ++ return; ++ } + +- if (enable_ibt != ibt_enabled || enable_shstk != shstk_enabled) +- { +- if (!program) +- { +- 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; +- +- if (!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 +- { +- 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. */ +- GL(dl_x86_feature_1) &= ~cet_feature; +- +- cet_feature_changed = true; +- } ++ unsigned int disable_feature_1 = 0; ++ unsigned int legacy_obj = 0; ++ const char *msg = NULL; + +-#ifdef SHARED +- if (program && (ibt_enabled || shstk_enabled)) ++ if ((info->feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0 ++ && (info->feature_1_legacy ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0) ++ { ++ if (info->enable_ibt_type != cet_permissive) + { +- 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; ++ legacy_obj = info->feature_1_legacy_ibt; ++ msg = N_("rebuild shared object with IBT support enabled"); + } +-#endif ++ else ++ disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_IBT; ++ } + +- if (cet_feature_changed) ++ /* Check the next feature only if there is no error. */ ++ if (msg == NULL ++ && (info->feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0 ++ && (info->feature_1_legacy ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0) ++ { ++ if (info->enable_shstk_type != cet_permissive) + { +- 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); ++ legacy_obj = info->feature_1_legacy_shstk; ++ msg = N_("rebuild shared object with SHSTK support enabled"); + } ++ else ++ disable_feature_1 |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ } ++ ++ /* If there is an error, long jump back to the caller. */ ++ if (msg != NULL) ++ _dl_signal_error (0, m->l_initfini[legacy_obj]->l_name, "dlopen", ++ msg); ++ ++ if (disable_feature_1 != 0) ++ { ++ int res = dl_cet_disable_cet (disable_feature_1); ++ if (res) ++ { ++ if ((disable_feature_1 ++ & GNU_PROPERTY_X86_FEATURE_1_IBT) != 0) ++ msg = N_("can't disable IBT"); ++ else ++ msg = N_("can't disable SHSTK"); ++ /* Long jump back to the caller on error. */ ++ _dl_signal_error (-res, m->l_initfini[legacy_obj]->l_name, ++ "dlopen", msg); ++ } ++ ++ /* Clear the disabled bits in dl_x86_feature_1. */ ++ GL(dl_x86_feature_1) &= ~disable_feature_1; ++ ++ THREAD_SETMEM (THREAD_SELF, header.feature_1, ++ GL(dl_x86_feature_1)); ++ } ++} ++ ++static void ++dl_cet_check (struct link_map *m, const char *program) ++{ ++ struct dl_cet_info info; ++ ++ /* Check how IBT and SHSTK should be enabled. */ ++ info.enable_ibt_type = GL(dl_x86_feature_control).ibt; ++ info.enable_shstk_type = GL(dl_x86_feature_control).shstk; ++ ++ info.feature_1_enabled = GL(dl_x86_feature_1); ++ ++ /* No legacy object check if IBT and SHSTK are always on. */ ++ if (info.enable_ibt_type == cet_always_on ++ && info.enable_shstk_type == cet_always_on) ++ { ++#ifdef SHARED ++ /* Set it only during startup. */ ++ if (program != NULL) ++ THREAD_SETMEM (THREAD_SELF, header.feature_1, ++ info.feature_1_enabled); ++#endif ++ return; + } ++ ++ /* Check if IBT and SHSTK were enabled by kernel. */ ++ if (info.feature_1_enabled == 0) ++ return; ++ ++ info.program = program; ++ ++ /* Check which features should be enabled. */ ++ info.enable_feature_1 = 0; ++ if (info.enable_ibt_type != cet_always_off) ++ info.enable_feature_1 |= (info.feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_IBT); ++ if (info.enable_shstk_type != cet_always_off) ++ info.enable_feature_1 |= (info.feature_1_enabled ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK); ++ ++ /* Start with no legacy objects. */ ++ info.feature_1_legacy = 0; ++ info.feature_1_legacy_ibt = 0; ++ info.feature_1_legacy_shstk = 0; ++ ++#ifdef SHARED ++ if (program) ++ dl_cet_check_startup (m, &info); ++ else ++#endif ++ dl_cet_check_dlopen (m, &info); + } + + void +-- +2.40.1 + diff --git a/v2-0011-x86-64-Add-fixup-asm-unistd.h-and-regenerate-arch.patch b/v2-0011-x86-64-Add-fixup-asm-unistd.h-and-regenerate-arch.patch new file mode 100644 index 0000000..1dc95c0 --- /dev/null +++ b/v2-0011-x86-64-Add-fixup-asm-unistd.h-and-regenerate-arch.patch @@ -0,0 +1,96 @@ +From da84f75756ca022e84be6fefd2b8167852949612 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 7 Jan 2022 14:31:25 -0800 +Subject: [PATCH v2 11/15] x86-64: Add and regenerate + arch-syscall.h + +Add the map_shadow_stack system call to Linux/x86-64. +--- + sysdeps/unix/sysv/linux/syscall-names.list | 1 + + .../unix/sysv/linux/x86_64/64/arch-syscall.h | 1 + + .../sysv/linux/x86_64/64/fixup-asm-unistd.h | 20 +++++++++++++++++++ + .../unix/sysv/linux/x86_64/x32/arch-syscall.h | 1 + + .../sysv/linux/x86_64/x32/fixup-asm-unistd.h | 4 ++++ + 5 files changed, 27 insertions(+) + create mode 100644 sysdeps/unix/sysv/linux/x86_64/64/fixup-asm-unistd.h + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 5d27b5279c..2bb924c8c4 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -245,6 +245,7 @@ lsetxattr + lstat + lstat64 + madvise ++map_shadow_stack + mbind + membarrier + memfd_create +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index b4ab892ec1..c09890ab74 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -152,6 +152,7 @@ + #define __NR_lsetxattr 189 + #define __NR_lstat 6 + #define __NR_madvise 28 ++#define __NR_map_shadow_stack 451 + #define __NR_mbind 237 + #define __NR_membarrier 324 + #define __NR_memfd_create 319 +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/fixup-asm-unistd.h b/sysdeps/unix/sysv/linux/x86_64/64/fixup-asm-unistd.h +new file mode 100644 +index 0000000000..20d941796d +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86_64/64/fixup-asm-unistd.h +@@ -0,0 +1,20 @@ ++/* Regularize definitions. X86-64/64 version. ++ Copyright (C) 2023 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 __NR_map_shadow_stack ++# define __NR_map_shadow_stack 451 ++#endif +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 772559c87b..7ad88cb20d 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -146,6 +146,7 @@ + #define __NR_lsetxattr 1073742013 + #define __NR_lstat 1073741830 + #define __NR_madvise 1073741852 ++#define __NR_map_shadow_stack 1073742275 + #define __NR_mbind 1073742061 + #define __NR_membarrier 1073742148 + #define __NR_memfd_create 1073742143 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h +index ae854321a2..882a2ad8c8 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h +@@ -15,6 +15,10 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef __NR_map_shadow_stack ++# define __NR_map_shadow_stack 1073742275 ++#endif ++ + /* X32 uses the same 64-bit syscall interface for set_thread_area. */ + #ifndef __NR_set_thread_area + # define __NR_set_thread_area 1073742029 +-- +2.40.1 + diff --git a/v2-0012-x86-cet-Sync-with-the-kernel-shadow-stack-interfa.patch b/v2-0012-x86-cet-Sync-with-the-kernel-shadow-stack-interfa.patch new file mode 100644 index 0000000..7b80049 --- /dev/null +++ b/v2-0012-x86-cet-Sync-with-the-kernel-shadow-stack-interfa.patch @@ -0,0 +1,803 @@ +From fc14bc65a7e0d3fbe5d939272f25d2e81100e44a Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 15 Aug 2020 08:04:23 -0700 +Subject: [PATCH v2 12/15] x86/cet: Sync with the kernel shadow stack interface + +Sync with the upstream shadow stack kernel. Although shadow stack is +only supported for x86-64, the i386 shadow stack support is also adjusted. +Don't enable CET for i386 since CET won't work on i386. + +1. When the shadow stack base in TCB is unset, the default shadow stack +is in use. Use the current shadow stack pointer as the marker for the +default shadow stack. +2. Allocate shadow stack with the map_shadow_stack syscall. +3. Rename arch_prctl CET commands to ARCH_SHSTK_XXX. +4. Rewrite the CET control functions with the current kernel shadow stack +interface. + +Since CET is no longer enabled by kernel, a separate patch will enable +shadow stack during startup. +--- + sysdeps/i386/nptl/tls.h | 2 +- + sysdeps/unix/sysv/linux/i386/getcontext.S | 28 +----- + sysdeps/unix/sysv/linux/i386/makecontext.S | 88 +++++++------------ + sysdeps/unix/sysv/linux/i386/swapcontext.S | 22 +---- + sysdeps/unix/sysv/linux/x86/Makefile | 1 + + .../sysv/linux/x86/allocate-shadow-stack.c | 54 ++++++++++++ + .../sysv/linux/x86/allocate-shadow-stack.h | 27 ++++++ + sysdeps/unix/sysv/linux/x86/bits/mman.h | 5 ++ + sysdeps/unix/sysv/linux/x86/cpu-features.c | 13 ++- + sysdeps/unix/sysv/linux/x86/dl-cet.h | 16 +++- + .../unix/sysv/linux/x86/include/asm/prctl.h | 37 ++++---- + .../sysv/linux/x86/tst-cet-setcontext-1.c | 17 ++-- + .../unix/sysv/linux/x86_64/__start_context.S | 38 ++------ + sysdeps/unix/sysv/linux/x86_64/getcontext.S | 30 ++----- + sysdeps/unix/sysv/linux/x86_64/makecontext.c | 29 +++--- + sysdeps/unix/sysv/linux/x86_64/swapcontext.S | 22 +---- + sysdeps/x86/cpu-features.c | 15 ++-- + sysdeps/x86/dl-cet.c | 2 +- + sysdeps/x86_64/nptl/tls.h | 2 +- + 19 files changed, 218 insertions(+), 230 deletions(-) + create mode 100644 sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.c + create mode 100644 sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.h + +diff --git a/sysdeps/i386/nptl/tls.h b/sysdeps/i386/nptl/tls.h +index 95e7c5be51..da4b83dd49 100644 +--- a/sysdeps/i386/nptl/tls.h ++++ b/sysdeps/i386/nptl/tls.h +@@ -49,7 +49,7 @@ typedef struct + void *__private_tm[3]; + /* GCC split stack support. */ + void *__private_ss; +- /* The lowest address of shadow stack, */ ++ /* The marker for the current shadow stack. */ + unsigned long ssp_base; + } tcbhead_t; + +diff --git a/sysdeps/unix/sysv/linux/i386/getcontext.S b/sysdeps/unix/sysv/linux/i386/getcontext.S +index b69a73847b..49ece43dd2 100644 +--- a/sysdeps/unix/sysv/linux/i386/getcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/getcontext.S +@@ -54,31 +54,11 @@ ENTRY(__getcontext) + 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 ++ /* When the shadow stack base is unset, the default shadow ++ stack is in use. Use the current shadow stack pointer ++ as the marker for the default shadow stack. */ ++ rdsspd %eax + movl %eax, %gs:SSP_BASE_OFFSET +- add $24, %esp + + L(shadow_stack_bound_recorded): + /* Load address of the context data structure. */ +diff --git a/sysdeps/unix/sysv/linux/i386/makecontext.S b/sysdeps/unix/sysv/linux/i386/makecontext.S +index 346cdd0e0a..bf481420dc 100644 +--- a/sysdeps/unix/sysv/linux/i386/makecontext.S ++++ b/sysdeps/unix/sysv/linux/i386/makecontext.S +@@ -73,28 +73,37 @@ ENTRY(__makecontext) + 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. Load the pointer to ucontext in ++ ECX. */ ++ movl 4(%esp), %ecx ++ ++ /* Pass the address of __ssp[1] in EDX. */ ++ leal (oSSP + 4)(%ecx), %edx ++ /* Pass stack size in EAX. */ ++ movl oSS_SIZE(%ecx), %eax ++ ++ /* Call __allocate_shadow_stack to allocate a new shadow stack. */ ++ call __allocate_shadow_stack ++ /* Check for error return. */ ++ testl %eax, %eax ++ jne L(hlt) /* This should never happen. */ + +- /* 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 ++ /* Reload the pointer to ucontext into ECX. */ ++ movl 4(%esp), %ecx + +- /* Align shadow stack size to 8 bytes. */ +- addl $7, %edx +- andl $-8, %edx ++ /* Load the base address of the new shadow stack into EAX. */ ++ movl (oSSP + 4)(%ecx), %eax + +- /* Store shadow stack size in __ssp[2]. */ +- movl %edx, (oSSP + 8)(%eax) ++ /* Store the new shadow stack pointer, the shadow stack base + ++ the shadow stack size - 4, in __ssp[0]. */ ++ addl (oSSP + 8)(%ecx), %eax ++ subl $4, %eax ++ movl %eax, oSSP(%ecx) + + /* Save ESI in the second scratch register slot. */ +- movl %esi, oSCRATCH2(%eax) ++ movl %esi, oSCRATCH2(%ecx) + /* Save EDI in the third scratch register slot. */ +- movl %edi, oSCRATCH3(%eax) +- +- /* Save the pointer to ucontext. */ +- movl %eax, %edi ++ movl %edi, oSCRATCH3(%ecx) + + /* Get the original shadow stack pointer. */ + rdsspd %esi +@@ -104,7 +113,7 @@ ENTRY(__makecontext) + andl $-8, %esi + + /* Load the top of the new stack into EDX. */ +- movl oESP(%eax), %edx ++ movl oESP(%ecx), %edx + + /* We need to terminate the FDE here because the unwinder looks + at ra-1 for unwind information. */ +@@ -118,39 +127,14 @@ ENTRY(__makecontext) + 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 ++ /* Load the new shadow stack base in __ssp[1] into EAX. */ ++ movl (oSSP + 4)(%ecx), %eax + +- /* 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 ++ /* Load the new shadow stack size in __ssp[2] into EDI. */ ++ movl (oSSP + 8)(%ecx), %edi + + /* Use the restore stoken to restore the new shadow stack. */ +- rstorssp -8(%eax, %ecx) ++ rstorssp -8(%eax, %edi) + + /* Save the restore token at the next 8 byte aligned boundary + on the original shadow stack. */ +@@ -162,27 +146,21 @@ ENTRY(__makecontext) + 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 ++ movl oSCRATCH2(%ecx), %esi + /* Restore EDI from the third scratch register slot. */ +- movl oSCRATCH3(%edi), %edi ++ movl oSCRATCH3(%ecx), %edi + + ret + +diff --git a/sysdeps/unix/sysv/linux/i386/swapcontext.S b/sysdeps/unix/sysv/linux/i386/swapcontext.S +index 551df10c91..d4f31fa5d5 100644 +--- a/sysdeps/unix/sysv/linux/i386/swapcontext.S ++++ b/sysdeps/unix/sysv/linux/i386/swapcontext.S +@@ -85,25 +85,11 @@ ENTRY(__swapcontext) + 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 ++ /* When the shadow stack base is unset, the default shadow ++ stack is in use. Use the current shadow stack pointer ++ as the marker for the default shadow stack. */ ++ rdsspd %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. */ +diff --git a/sysdeps/unix/sysv/linux/x86/Makefile b/sysdeps/unix/sysv/linux/x86/Makefile +index 9dfdd689a9..ed0d6500b9 100644 +--- a/sysdeps/unix/sysv/linux/x86/Makefile ++++ b/sysdeps/unix/sysv/linux/x86/Makefile +@@ -44,6 +44,7 @@ CFLAGS-tst-cet-vfork-1.c += -mshstk + endif + + ifeq ($(subdir),stdlib) ++sysdep_routines += allocate-shadow-stack + tests += tst-cet-setcontext-1 + CFLAGS-tst-cet-setcontext-1.c += -mshstk + endif +diff --git a/sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.c b/sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.c +new file mode 100644 +index 0000000000..3a76db1a60 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.c +@@ -0,0 +1,54 @@ ++/* Helper function to allocate shadow stack. ++ Copyright (C) 2023 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 ++ ++/* NB: This can be treated as a syscall by caller. */ ++ ++#ifndef __x86_64__ ++__attribute__ ((regparm (2))) ++#endif ++long int ++__allocate_shadow_stack (size_t stack_size, ++ shadow_stack_size_t *child_stack) ++{ ++#ifdef __NR_map_shadow_stack ++ size_t shadow_stack_size ++ = stack_size >> STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT; ++ /* Align shadow stack to 8 bytes. */ ++ shadow_stack_size = ALIGN_UP (shadow_stack_size, 8); ++ void *shadow_stack = (void *)INLINE_SYSCALL_CALL ++ (map_shadow_stack, NULL, shadow_stack_size, SHADOW_STACK_SET_TOKEN); ++ /* Report the map_shadow_stack error. */ ++ if (shadow_stack == MAP_FAILED) ++ return -errno; ++ ++ /* Save the shadow stack base and size on child stack. */ ++ child_stack[0] = (uintptr_t) shadow_stack; ++ child_stack[1] = shadow_stack_size; ++ ++ return 0; ++#else ++ return -ENOSYS; ++#endif ++} +diff --git a/sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.h b/sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.h +new file mode 100644 +index 0000000000..834373e0d3 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86/allocate-shadow-stack.h +@@ -0,0 +1,27 @@ ++/* Helper function to allocate shadow stack. ++ Copyright (C) 2023 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 ++ ++typedef __typeof (((ucontext_t *) 0)->__ssp[0]) shadow_stack_size_t; ++ ++extern long int __allocate_shadow_stack (size_t, shadow_stack_size_t *) ++#ifndef __x86_64__ ++ __attribute__ ((regparm (2))) ++#endif ++ attribute_hidden; +diff --git a/sysdeps/unix/sysv/linux/x86/bits/mman.h b/sysdeps/unix/sysv/linux/x86/bits/mman.h +index b335ceff43..17bb078375 100644 +--- a/sysdeps/unix/sysv/linux/x86/bits/mman.h ++++ b/sysdeps/unix/sysv/linux/x86/bits/mman.h +@@ -26,6 +26,11 @@ + /* Other flags. */ + #define MAP_32BIT 0x40 /* Only give out 32-bit addresses. */ + ++#ifdef __USE_MISC ++/* Set up a restore token in the newly allocatd shadow stack */ ++# define SHADOW_STACK_SET_TOKEN 0x1 ++#endif ++ + #include + + /* Include generic Linux declarations. */ +diff --git a/sysdeps/unix/sysv/linux/x86/cpu-features.c b/sysdeps/unix/sysv/linux/x86/cpu-features.c +index 41e7600668..0e6e2bf855 100644 +--- a/sysdeps/unix/sysv/linux/x86/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/x86/cpu-features.c +@@ -23,10 +23,15 @@ + static inline int __attribute__ ((always_inline)) + get_cet_status (void) + { +- unsigned long long cet_status[3]; +- if (INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_CET_STATUS, cet_status) == 0) +- return cet_status[0]; +- return 0; ++ unsigned long long kernel_feature; ++ unsigned int status = 0; ++ if (INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_STATUS, ++ &kernel_feature) == 0) ++ { ++ if ((kernel_feature & ARCH_SHSTK_SHSTK) != 0) ++ status = GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ } ++ return status; + } + + # ifndef SHARED +diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.h b/sysdeps/unix/sysv/linux/x86/dl-cet.h +index c885bf1323..da220ac627 100644 +--- a/sysdeps/unix/sysv/linux/x86/dl-cet.h ++++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h +@@ -21,12 +21,20 @@ + static inline int __attribute__ ((always_inline)) + dl_cet_disable_cet (unsigned int cet_feature) + { +- return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_CET_DISABLE, +- cet_feature); ++ if (cet_feature != GNU_PROPERTY_X86_FEATURE_1_SHSTK) ++ return -1; ++ long long int kernel_feature = ARCH_SHSTK_SHSTK; ++ return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_DISABLE, ++ kernel_feature); + } + + static inline int __attribute__ ((always_inline)) +-dl_cet_lock_cet (void) ++dl_cet_lock_cet (unsigned int cet_feature) + { +- return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_CET_LOCK, 0); ++ if (cet_feature != GNU_PROPERTY_X86_FEATURE_1_SHSTK) ++ return -1; ++ /* Lock all SHSTK features. */ ++ long long int kernel_feature = -1; ++ return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_LOCK, ++ kernel_feature); + } +diff --git a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +index 45ad0b052f..2f511321ad 100644 +--- a/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h ++++ b/sysdeps/unix/sysv/linux/x86/include/asm/prctl.h +@@ -4,24 +4,19 @@ + + #include_next + +-#ifndef ARCH_CET_STATUS +-/* CET features: +- IBT: GNU_PROPERTY_X86_FEATURE_1_IBT +- SHSTK: GNU_PROPERTY_X86_FEATURE_1_SHSTK +- */ +-/* Return CET features in unsigned long long *addr: +- features: addr[0]. +- shadow stack base address: addr[1]. +- shadow stack size: addr[2]. +- */ +-# define ARCH_CET_STATUS 0x3001 +-/* Disable CET features in unsigned int features. */ +-# define ARCH_CET_DISABLE 0x3002 +-/* Lock all CET features. */ +-# define ARCH_CET_LOCK 0x3003 +-/* Allocate a new shadow stack with unsigned long long *addr: +- IN: requested shadow stack size: *addr. +- OUT: allocated shadow stack address: *addr. +- */ +-# define ARCH_CET_ALLOC_SHSTK 0x3004 +-#endif /* ARCH_CET_STATUS */ ++#ifndef ARCH_SHSTK_ENABLE ++/* Enable SHSTK features in unsigned long int features. */ ++# define ARCH_SHSTK_ENABLE 0x5001 ++/* Disable SHSTK features in unsigned long int features. */ ++# define ARCH_SHSTK_DISABLE 0x5002 ++/* Lock SHSTK features in unsigned long int features. */ ++# define ARCH_SHSTK_LOCK 0x5003 ++/* Unlock SHSTK features in unsigned long int features. */ ++# define ARCH_SHSTK_UNLOCK 0x5004 ++/* Return SHSTK features in unsigned long int features. */ ++# define ARCH_SHSTK_STATUS 0x5005 ++ ++/* ARCH_SHSTK_ features bits */ ++# define ARCH_SHSTK_SHSTK 0x1 ++# define ARCH_SHSTK_WRSS 0x2 ++#endif +diff --git a/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c b/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c +index 837a9fd0eb..2ea66c803b 100644 +--- a/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c ++++ b/sysdeps/unix/sysv/linux/x86/tst-cet-setcontext-1.c +@@ -87,15 +87,14 @@ do_test (void) + ctx[4].uc_link = &ctx[0]; + makecontext (&ctx[4], (void (*) (void)) f1, 0); + +- /* NB: When shadow stack is enabled, makecontext calls arch_prctl +- with ARCH_CET_ALLOC_SHSTK to allocate a new shadow stack which +- can be unmapped. The base address and size of the new shadow +- stack are returned in __ssp[1] and __ssp[2]. makecontext is +- called for CTX1, CTX3 and CTX4. But only CTX1 is used. New +- shadow stacks are allocated in the order of CTX3, CTX1, CTX4. +- It is very likely that CTX1's shadow stack is placed between +- CTX3 and CTX4. We munmap CTX3's and CTX4's shadow stacks to +- create gaps above and below CTX1's shadow stack. We check ++ /* NB: When shadow stack is enabled, makecontext calls map_shadow_stack ++ to allocate a new shadow stack which can be unmapped. The base ++ address and size of the new shadow stack are returned in __ssp[1] ++ and __ssp[2]. makecontext is called for CTX1, CTX3 and CTX4. But ++ only CTX1 is used. New shadow stacks are allocated in the order ++ of CTX3, CTX1, CTX4. It is very likely that CTX1's shadow stack is ++ placed between CTX3 and CTX4. We munmap CTX3's and CTX4's shadow ++ stacks to create gaps above and below CTX1's shadow stack. We check + that setcontext CTX1 works correctly in this case. */ + if (_get_ssp () != 0) + { +diff --git a/sysdeps/unix/sysv/linux/x86_64/__start_context.S b/sysdeps/unix/sysv/linux/x86_64/__start_context.S +index f6436dd6bb..ae04203c90 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/__start_context.S ++++ b/sysdeps/unix/sysv/linux/x86_64/__start_context.S +@@ -24,20 +24,14 @@ + /* Use CALL to push __start_context onto the new stack as well as the new + shadow stack. RDI points to ucontext: + Incoming: +- __ssp[0]: The original caller's shadow stack pointer. +- __ssp[1]: The size of the new shadow stack. +- __ssp[2]: The size of the new shadow stack. +- Outgoing: + __ssp[0]: The new shadow stack pointer. + __ssp[1]: The base address of the new shadow stack. + __ssp[2]: The size of the new shadow stack. + */ + + ENTRY(__push___start_context) +- /* Save the pointer to ucontext. */ +- movq %rdi, %r9 + /* Get the original shadow stack pointer. */ +- rdsspq %r8 ++ rdsspq %rcx + /* Save the original stack pointer. */ + movq %rsp, %rdx + /* Load the top of the new stack into RSI. */ +@@ -45,24 +39,12 @@ ENTRY(__push___start_context) + /* Add 8 bytes to RSI since CALL will push the 8-byte return + address onto stack. */ + leaq 8(%rsi), %rsp +- /* Allocate the new shadow stack. The size of the new shadow +- stack is passed in __ssp[1]. */ +- lea (oSSP + 8)(%rdi), %RSI_LP +- movl $ARCH_CET_ALLOC_SHSTK, %edi +- movl $__NR_arch_prctl, %eax +- /* The new shadow stack base is returned in __ssp[1]. */ +- syscall +- testq %rax, %rax +- jne L(hlt) /* This should never happen. */ +- +- /* Get the size of the new shadow stack. */ +- movq 8(%rsi), %rdi +- +- /* Get the base address of the new shadow stack. */ +- movq (%rsi), %rsi +- ++ /* The size of the new shadow stack is stored in __ssp[2]. */ ++ mov (oSSP + 16)(%rdi), %RSI_LP ++ /* The new shadow stack base is stored in __ssp[1]. */ ++ mov (oSSP + 8)(%rdi), %RAX_LP + /* Use the restore stoken to restore the new shadow stack. */ +- rstorssp -8(%rsi, %rdi) ++ rstorssp -8(%rax, %rsi) + + /* Save the restore token on the original shadow stack. */ + saveprevssp +@@ -73,18 +55,12 @@ ENTRY(__push___start_context) + jmp __start_context + 1: + +- /* Get the new shadow stack pointer. */ +- rdsspq %rdi +- + /* Use the restore stoken to restore the original shadow stack. */ +- rstorssp -8(%r8) ++ rstorssp -8(%rcx) + + /* Save the restore token on the new shadow stack. */ + saveprevssp + +- /* Store the new shadow stack pointer in __ssp[0]. */ +- movq %rdi, oSSP(%r9) +- + /* Restore the original stack. */ + mov %rdx, %rsp + ret +diff --git a/sysdeps/unix/sysv/linux/x86_64/getcontext.S b/sysdeps/unix/sysv/linux/x86_64/getcontext.S +index a00e2f6290..71f3802dca 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/getcontext.S ++++ b/sysdeps/unix/sysv/linux/x86_64/getcontext.S +@@ -58,35 +58,15 @@ ENTRY(__getcontext) + testl $X86_FEATURE_1_SHSTK, %fs:FEATURE_1_OFFSET + jz L(no_shstk) + +- /* Save RDI in RDX which won't be clobbered by syscall. */ +- movq %rdi, %rdx +- + xorl %eax, %eax + cmpq %fs:SSP_BASE_OFFSET, %rax + 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, %RSP_LP +- mov %RSP_LP, %RSI_LP +- movl $ARCH_CET_STATUS, %edi +- movl $__NR_arch_prctl, %eax +- syscall +- testq %rax, %rax +- jz L(continue_no_err) +- +- /* This should never happen. */ +- hlt +- +-L(continue_no_err): +- /* Record the base of the current shadow stack. */ +- movq 8(%rsp), %rax ++ /* When the shadow stack base is unset, the default shadow ++ stack is in use. Use the current shadow stack pointer ++ as the marker for the default shadow stack. */ ++ rdsspq %rax + movq %rax, %fs:SSP_BASE_OFFSET +- add $24, %RSP_LP +- +- /* Restore RDI. */ +- movq %rdx, %rdi + + L(shadow_stack_bound_recorded): + /* Get the current shadow stack pointer. */ +@@ -94,7 +74,7 @@ L(shadow_stack_bound_recorded): + /* NB: Save the caller's shadow stack so that we can jump back + to the caller directly. */ + addq $8, %rax +- movq %rax, oSSP(%rdx) ++ movq %rax, oSSP(%rdi) + + /* Save the current shadow stack base in ucontext. */ + movq %fs:SSP_BASE_OFFSET, %rax +diff --git a/sysdeps/unix/sysv/linux/x86_64/makecontext.c b/sysdeps/unix/sysv/linux/x86_64/makecontext.c +index de9e03eb81..788b730132 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/makecontext.c ++++ b/sysdeps/unix/sysv/linux/x86_64/makecontext.c +@@ -24,6 +24,8 @@ + # include + # include + # include ++# include ++# include + #endif + + #include "ucontext_i.h" +@@ -88,23 +90,24 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) + if ((feature_1 & X86_FEATURE_1_SHSTK) != 0) + { + /* Shadow stack is enabled. We need to allocate a new shadow +- stack. */ +- unsigned long ssp_size = (((uintptr_t) sp +- - (uintptr_t) ucp->uc_stack.ss_sp) +- >> STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT); +- /* Align shadow stack to 8 bytes. */ +- ssp_size = ALIGN_UP (ssp_size, 8); +- +- ucp->__ssp[1] = ssp_size; +- ucp->__ssp[2] = ssp_size; +- +- /* Call __push___start_context to allocate a new shadow stack, +- push __start_context onto the new stack as well as the new +- shadow stack. NB: After __push___start_context returns, ++ stack. NB: + ucp->__ssp[0]: The new shadow stack pointer. + ucp->__ssp[1]: The base address of the new shadow stack. + ucp->__ssp[2]: The size of the new shadow stack. + */ ++ long int ret ++ = __allocate_shadow_stack (((uintptr_t) sp ++ - (uintptr_t) ucp->uc_stack.ss_sp), ++ &ucp->__ssp[1]); ++ if (ret != 0) ++ { ++ /* FIXME: What should we do? */ ++ abort (); ++ } ++ ++ ucp->__ssp[0] = ucp->__ssp[1] + ucp->__ssp[2] - 8; ++ /* Call __push___start_context to push __start_context onto the new ++ stack as well as the new shadow stack. */ + __push___start_context (ucp); + } + else +diff --git a/sysdeps/unix/sysv/linux/x86_64/swapcontext.S b/sysdeps/unix/sysv/linux/x86_64/swapcontext.S +index 5925752164..2f2fe9875b 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/swapcontext.S ++++ b/sysdeps/unix/sysv/linux/x86_64/swapcontext.S +@@ -109,25 +109,11 @@ ENTRY(__swapcontext) + cmpq %fs:SSP_BASE_OFFSET, %rax + 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, %RSP_LP +- mov %RSP_LP, %RSI_LP +- movl $ARCH_CET_STATUS, %edi +- movl $__NR_arch_prctl, %eax +- syscall +- testq %rax, %rax +- jz L(continue_no_err) +- +- /* This should never happen. */ +- hlt +- +-L(continue_no_err): +- /* Record the base of the current shadow stack. */ +- movq 8(%rsp), %rax ++ /* When the shadow stack base is unset, the default shadow ++ stack is in use. Use the current shadow stack pointer ++ as the marker for the default shadow stack. */ ++ rdsspq %rax + movq %rax, %fs:SSP_BASE_OFFSET +- add $24, %RSP_LP + + L(shadow_stack_bound_recorded): + /* If we unwind the stack, we can't undo stack unwinding. Just +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 5bff8ec0b4..6c0d6c100d 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -851,8 +851,9 @@ no_cpuid: + + # 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)) ++ if ((cet_status ++ & (GNU_PROPERTY_X86_FEATURE_1_IBT ++ | GNU_PROPERTY_X86_FEATURE_1_SHSTK))) + { + /* Disable IBT and/or SHSTK if they are enabled by kernel, but + disabled by environment variable: +@@ -861,9 +862,11 @@ no_cpuid: + */ + unsigned int cet_feature = 0; + if (!CPU_FEATURE_USABLE (IBT)) +- cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; ++ cet_feature |= (cet_status ++ & GNU_PROPERTY_X86_FEATURE_1_IBT); + if (!CPU_FEATURE_USABLE (SHSTK)) +- cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ cet_feature |= (cet_status ++ & GNU_PROPERTY_X86_FEATURE_1_SHSTK); + + if (cet_feature) + { +@@ -878,7 +881,9 @@ no_cpuid: + 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 (); ++ dl_cet_lock_cet (GL(dl_x86_feature_1) ++ & (GNU_PROPERTY_X86_FEATURE_1_IBT ++ | GNU_PROPERTY_X86_FEATURE_1_SHSTK)); + } + # endif + } +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 67c51ee8c2..8b911fd931 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -201,7 +201,7 @@ dl_cet_check_startup (struct link_map *m, struct dl_cet_info *info) + feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + + if (feature_1_lock != 0 +- && dl_cet_lock_cet () != 0) ++ && dl_cet_lock_cet (feature_1_lock) != 0) + _dl_fatal_printf ("%s: can't lock CET\n", info->program); + } + +diff --git a/sysdeps/x86_64/nptl/tls.h b/sysdeps/x86_64/nptl/tls.h +index 1403f939f7..4bcc2552a1 100644 +--- a/sysdeps/x86_64/nptl/tls.h ++++ b/sysdeps/x86_64/nptl/tls.h +@@ -60,7 +60,7 @@ typedef struct + void *__private_tm[4]; + /* GCC split stack support. */ + void *__private_ss; +- /* The lowest address of shadow stack, */ ++ /* The marker for the current shadow stack. */ + unsigned long long int ssp_base; + /* Must be kept even if it is no longer used by glibc since programs, + like AddressSanitizer, depend on the size of tcbhead_t. */ +-- +2.40.1 + diff --git a/v2-0013-elf-Always-provide-_dl_get_dl_main_map-in-libc.a.patch b/v2-0013-elf-Always-provide-_dl_get_dl_main_map-in-libc.a.patch new file mode 100644 index 0000000..a39200d --- /dev/null +++ b/v2-0013-elf-Always-provide-_dl_get_dl_main_map-in-libc.a.patch @@ -0,0 +1,59 @@ +From dfb1d9949aca739933464bde8710375358536047 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 14 Jan 2022 06:04:25 -0800 +Subject: [PATCH v2 13/15] elf: Always provide _dl_get_dl_main_map in libc.a + +Always provide _dl_get_dl_main_map in libc.a. It will be used by x86 +to process PT_GNU_PROPERTY segment. +--- + elf/dl-support.c | 2 -- + sysdeps/generic/ldsodefs.h | 8 ++++---- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 322599916f..042be8a433 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -353,7 +353,6 @@ _dl_non_dynamic_init (void) + DL_SYSINFO_IMPLEMENTATION + #endif + +-#if ENABLE_STATIC_PIE + /* Since relocation to hidden _dl_main_map causes relocation overflow on + aarch64, a function is used to get the address of _dl_main_map. */ + +@@ -362,7 +361,6 @@ _dl_get_dl_main_map (void) + { + return &_dl_main_map; + } +-#endif + + /* This is used by _dl_runtime_profile, not used on static code. */ + void +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index ba53176296..7a0903cb8a 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1172,15 +1172,15 @@ void __libc_setup_tls (void); + # if ENABLE_STATIC_PIE + /* Relocate static executable with PIE. */ + extern void _dl_relocate_static_pie (void) attribute_hidden; +- +-/* Get a pointer to _dl_main_map. */ +-extern struct link_map * _dl_get_dl_main_map (void) +- __attribute__ ((visibility ("hidden"))); + # else + # define _dl_relocate_static_pie() + # endif + #endif + ++/* Get a pointer to _dl_main_map. */ ++extern struct link_map * _dl_get_dl_main_map (void) ++ __attribute__ ((visibility ("hidden"))); ++ + /* Perform early memory allocation, avoiding a TCB dependency. + Terminate the process if allocation fails. May attempt to use + brk. */ +-- +2.40.1 + diff --git a/v2-0014-x86-cet-Enable-shadow-stack-during-startup.patch b/v2-0014-x86-cet-Enable-shadow-stack-during-startup.patch new file mode 100644 index 0000000..535f499 --- /dev/null +++ b/v2-0014-x86-cet-Enable-shadow-stack-during-startup.patch @@ -0,0 +1,518 @@ +From 29b8bde6bbe322ea35f494b4f3dae3d5d55d3949 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 13 Jan 2022 15:35:07 -0800 +Subject: [PATCH v2 14/15] x86/cet: Enable shadow stack during startup + +Previously, CET was enabled by kernel before passing control to user +space and the startup code must disable CET if applications or shared +libraries aren't CET enabled. Since the current kernel only supports +shadow stack and won't enable shadow stack before passing control to +user space, we need to enable shadow stack during startup if the +application and all shared library are shadow stack enabled. There +is no need to disable shadow stack at startup. Shadow stack can only +be enabled in a function which will never return. Otherwise, shadow +stack will underflow at the function return. + +1. GL(dl_x86_feature_1) is set to the CET features which are supported +by the processor and are not disabled by the tunable. Only non-zero +features in GL(dl_x86_feature_1) should be enabled. After enabling +shadow stack with ARCH_SHSTK_ENABLE, ARCH_SHSTK_STATUS is used to check +if shadow stack is really enabled. +2. Use ARCH_SHSTK_ENABLE in RTLD_START in dynamic executable. It is +safe since RTLD_START never returns. +3. Call arch_prctl (ARCH_SHSTK_ENABLE) from ARCH_SETUP_TLS in static +executable. Since the start function using ARCH_SETUP_TLS never returns, +it is safe to enable shadow stack in ARCH_SETUP_TLS. +--- + sysdeps/unix/sysv/linux/x86/cpu-features.c | 49 -------------- + sysdeps/unix/sysv/linux/x86/dl-cet.h | 23 +++++++ + sysdeps/unix/sysv/linux/x86_64/dl-cet.h | 47 +++++++++++++ + sysdeps/x86/cpu-features-offsets.sym | 1 + + sysdeps/x86/cpu-features.c | 51 -------------- + sysdeps/x86/dl-cet.c | 77 +++++++++++----------- + sysdeps/x86/get-cpuid-feature-leaf.c | 2 +- + sysdeps/x86/include/cpu-features.h | 3 + + sysdeps/x86/libc-start.h | 54 ++++++++++++++- + sysdeps/x86_64/dl-machine.h | 12 +++- + sysdeps/x86_64/x32/dl-machine.h | 7 +- + 11 files changed, 180 insertions(+), 146 deletions(-) + delete mode 100644 sysdeps/unix/sysv/linux/x86/cpu-features.c + create mode 100644 sysdeps/unix/sysv/linux/x86_64/dl-cet.h + +diff --git a/sysdeps/unix/sysv/linux/x86/cpu-features.c b/sysdeps/unix/sysv/linux/x86/cpu-features.c +deleted file mode 100644 +index 0e6e2bf855..0000000000 +--- a/sysdeps/unix/sysv/linux/x86/cpu-features.c ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* Initialize CPU feature data for Linux/x86. +- This file is part of the GNU C Library. +- Copyright (C) 2018-2023 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 +- . */ +- +-#if CET_ENABLED +-# include +-# include +- +-static inline int __attribute__ ((always_inline)) +-get_cet_status (void) +-{ +- unsigned long long kernel_feature; +- unsigned int status = 0; +- if (INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_STATUS, +- &kernel_feature) == 0) +- { +- if ((kernel_feature & ARCH_SHSTK_SHSTK) != 0) +- status = GNU_PROPERTY_X86_FEATURE_1_SHSTK; +- } +- return status; +-} +- +-# ifndef SHARED +-static inline void +-x86_setup_tls (void) +-{ +- __libc_setup_tls (); +- THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); +-} +- +-# define ARCH_SETUP_TLS() x86_setup_tls () +-# endif +-#endif +- +-#include +diff --git a/sysdeps/unix/sysv/linux/x86/dl-cet.h b/sysdeps/unix/sysv/linux/x86/dl-cet.h +index da220ac627..634c885d33 100644 +--- a/sysdeps/unix/sysv/linux/x86/dl-cet.h ++++ b/sysdeps/unix/sysv/linux/x86/dl-cet.h +@@ -38,3 +38,26 @@ dl_cet_lock_cet (unsigned int cet_feature) + return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_LOCK, + kernel_feature); + } ++ ++static inline unsigned int __attribute__ ((always_inline)) ++dl_cet_get_cet_status (void) ++{ ++ unsigned long long kernel_feature; ++ unsigned int status = 0; ++ if (INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_STATUS, ++ &kernel_feature) == 0) ++ { ++ if ((kernel_feature & ARCH_SHSTK_SHSTK) != 0) ++ status = GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ } ++ return status; ++} ++ ++/* Enable shadow stack with a macro to avoid shadow stack underflow. */ ++#define ENABLE_X86_CET(cet_feature) \ ++ if ((cet_feature & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) \ ++ { \ ++ long long int kernel_feature = ARCH_SHSTK_SHSTK; \ ++ INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_SHSTK_ENABLE, \ ++ kernel_feature); \ ++ } +diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-cet.h b/sysdeps/unix/sysv/linux/x86_64/dl-cet.h +new file mode 100644 +index 0000000000..e23e05c6b8 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86_64/dl-cet.h +@@ -0,0 +1,47 @@ ++/* Linux/x86-64 CET initializers function. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include_next ++ ++#define X86_STRINGIFY_1(x) #x ++#define X86_STRINGIFY(x) X86_STRINGIFY_1 (x) ++ ++/* Enable shadow stack before calling _dl_init if it is enabled in ++ GL(dl_x86_feature_1). Call _dl_setup_x86_features to setup shadow ++ stack. */ ++#define RTLD_START_ENABLE_X86_FEATURES \ ++"\ ++ # Check if shadow stack is enabled in GL(dl_x86_feature_1).\n\ ++ movl _rtld_local+" X86_STRINGIFY (RTLD_GLOBAL_DL_X86_FEATURE_1_OFFSET) "(%rip), %edx\n\ ++ testl $" X86_STRINGIFY (X86_FEATURE_1_SHSTK) ", %edx\n\ ++ jz 1f\n\ ++ # Enable shadow stack if enabled in GL(dl_x86_feature_1).\n\ ++ movl $" X86_STRINGIFY (ARCH_SHSTK_SHSTK) ", %esi\n\ ++ movl $" X86_STRINGIFY (ARCH_SHSTK_ENABLE) ", %edi\n\ ++ movl $" X86_STRINGIFY (__NR_arch_prctl) ", %eax\n\ ++ syscall\n\ ++1:\n\ ++ # Pass GL(dl_x86_feature_1) to _dl_cet_setup_features.\n\ ++ movl %edx, %edi\n\ ++ # Align stack for the _dl_cet_setup_features call.\n\ ++ andq $-16, %rsp\n\ ++ call _dl_cet_setup_features\n\ ++ # Restore %rax and %rsp from %r12 and %r13.\n\ ++ movq %r12, %rax\n\ ++ movq %r13, %rsp\n\ ++" +diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym +index 6d03cea8e8..5429f60632 100644 +--- a/sysdeps/x86/cpu-features-offsets.sym ++++ b/sysdeps/x86/cpu-features-offsets.sym +@@ -4,3 +4,4 @@ + + RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET offsetof (struct rtld_global_ro, _dl_x86_cpu_features) + XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size) ++RTLD_GLOBAL_DL_X86_FEATURE_1_OFFSET offsetof (struct rtld_global, _dl_x86_feature_1) +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 6c0d6c100d..45bc7fcac3 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -836,57 +836,6 @@ no_cpuid: + TUNABLE_CALLBACK (set_x86_ibt)); + TUNABLE_GET (x86_shstk, tunable_val_t *, + TUNABLE_CALLBACK (set_x86_shstk)); +- +- /* Check CET status. */ +- unsigned int cet_status = get_cet_status (); +- +- if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_IBT) == 0) +- CPU_FEATURE_UNSET (cpu_features, IBT) +- if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_SHSTK) == 0) +- CPU_FEATURE_UNSET (cpu_features, SHSTK) +- +- if (cet_status) +- { +- GL(dl_x86_feature_1) = cet_status; +- +-# ifndef SHARED +- /* Check if IBT and SHSTK are enabled by kernel. */ +- if ((cet_status +- & (GNU_PROPERTY_X86_FEATURE_1_IBT +- | 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.cpu.hwcaps=-IBT,-SHSTK +- */ +- unsigned int cet_feature = 0; +- if (!CPU_FEATURE_USABLE (IBT)) +- cet_feature |= (cet_status +- & GNU_PROPERTY_X86_FEATURE_1_IBT); +- if (!CPU_FEATURE_USABLE (SHSTK)) +- cet_feature |= (cet_status +- & 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) &= ~cet_feature; +- } +- +- /* Lock CET if IBT or SHSTK is enabled in executable. Don't +- 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 (GL(dl_x86_feature_1) +- & (GNU_PROPERTY_X86_FEATURE_1_IBT +- | GNU_PROPERTY_X86_FEATURE_1_SHSTK)); +- } +-# endif +- } + #endif + + #ifndef SHARED +diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c +index 8b911fd931..7f37244d37 100644 +--- a/sysdeps/x86/dl-cet.c ++++ b/sysdeps/x86/dl-cet.c +@@ -172,40 +172,11 @@ dl_cet_check_startup (struct link_map *m, struct dl_cet_info *info) + = info->enable_feature_1 ^ info->feature_1_enabled; + if (disable_feature_1 != 0) + { +- /* Disable features in the kernel because of legacy objects or +- cet_always_off. */ +- if (dl_cet_disable_cet (disable_feature_1) != 0) +- _dl_fatal_printf ("%s: can't disable x86 Features\n", +- info->program); +- + /* Clear the disabled bits. Sync dl_x86_feature_1 and + info->feature_1_enabled with info->enable_feature_1. */ + info->feature_1_enabled = info->enable_feature_1; + GL(dl_x86_feature_1) = info->enable_feature_1; + } +- +- if (HAS_CPU_FEATURE (IBT) || HAS_CPU_FEATURE (SHSTK)) +- { +- /* Lock CET features only if IBT or SHSTK are enabled and are not +- enabled permissively. */ +- unsigned int feature_1_lock = 0; +- +- if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_IBT) +- != 0) +- && info->enable_ibt_type != cet_permissive) +- feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_IBT; +- +- if (((info->feature_1_enabled & GNU_PROPERTY_X86_FEATURE_1_SHSTK) +- != 0) +- && info->enable_shstk_type != cet_permissive) +- feature_1_lock |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; +- +- if (feature_1_lock != 0 +- && dl_cet_lock_cet (feature_1_lock) != 0) +- _dl_fatal_printf ("%s: can't lock CET\n", info->program); +- } +- +- THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); + } + #endif + +@@ -291,6 +262,15 @@ dl_cet_check (struct link_map *m, const char *program) + { + struct dl_cet_info info; + ++ /* CET is enabled only if RTLD_START_ENABLE_X86_FEATURES is defined. */ ++#if defined SHARED && defined RTLD_START_ENABLE_X86_FEATURES ++ /* Set dl_x86_feature_1 to features enabled in the executable. */ ++ if (program != NULL) ++ GL(dl_x86_feature_1) = (m->l_x86_feature_1_and ++ & (X86_FEATURE_1_IBT ++ | X86_FEATURE_1_SHSTK)); ++#endif ++ + /* Check how IBT and SHSTK should be enabled. */ + info.enable_ibt_type = GL(dl_x86_feature_control).ibt; + info.enable_shstk_type = GL(dl_x86_feature_control).shstk; +@@ -300,17 +280,9 @@ dl_cet_check (struct link_map *m, const char *program) + /* No legacy object check if IBT and SHSTK are always on. */ + if (info.enable_ibt_type == cet_always_on + && info.enable_shstk_type == cet_always_on) +- { +-#ifdef SHARED +- /* Set it only during startup. */ +- if (program != NULL) +- THREAD_SETMEM (THREAD_SELF, header.feature_1, +- info.feature_1_enabled); +-#endif +- return; +- } ++ return; + +- /* Check if IBT and SHSTK were enabled by kernel. */ ++ /* Check if IBT and SHSTK were enabled. */ + if (info.feature_1_enabled == 0) + return; + +@@ -344,6 +316,33 @@ _dl_cet_open_check (struct link_map *l) + dl_cet_check (l, NULL); + } + ++/* Set GL(dl_x86_feature_1) to the enabled features and clear the ++ active bits of the disabled features. */ ++ ++attribute_hidden ++void ++_dl_cet_setup_features (unsigned int cet_feature) ++{ ++ /* NB: cet_feature == GL(dl_x86_feature_1) which is set to features ++ enabled from executable, not necessarily supported by kernel. */ ++ if (cet_feature) ++ { ++ cet_feature = dl_cet_get_cet_status (); ++ /* Sync GL(dl_x86_feature_1) with kernel. */ ++ GL(dl_x86_feature_1) = cet_feature; ++ if (cet_feature) ++ { ++ THREAD_SETMEM (THREAD_SELF, header.feature_1, cet_feature); ++ ++ /* Lock CET if IBT or SHSTK is enabled in executable. Don't ++ 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 (cet_feature); ++ } ++ } ++} ++ + #ifdef SHARED + + # ifndef LINKAGE +diff --git a/sysdeps/x86/get-cpuid-feature-leaf.c b/sysdeps/x86/get-cpuid-feature-leaf.c +index 40a46cc79c..9317a6b494 100644 +--- a/sysdeps/x86/get-cpuid-feature-leaf.c ++++ b/sysdeps/x86/get-cpuid-feature-leaf.c +@@ -24,7 +24,7 @@ __x86_get_cpuid_feature_leaf (unsigned int leaf) + static const struct cpuid_feature feature = {}; + if (leaf < CPUID_INDEX_MAX) + return ((const struct cpuid_feature *) +- &GLRO(dl_x86_cpu_features).features[leaf]); ++ &GLRO(dl_x86_cpu_features).features[leaf]); + else + return &feature; + } +diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h +index 40b8129d6a..e6a2424682 100644 +--- a/sysdeps/x86/include/cpu-features.h ++++ b/sysdeps/x86/include/cpu-features.h +@@ -958,6 +958,9 @@ extern const struct cpu_features *_dl_x86_get_cpu_features (void) + # define INIT_ARCH() + # define _dl_x86_get_cpu_features() (&GLRO(dl_x86_cpu_features)) + extern void _dl_x86_init_cpu_features (void) attribute_hidden; ++ ++extern void _dl_cet_setup_features (unsigned int) ++ attribute_hidden; + #endif + + #ifdef __x86_64__ +diff --git a/sysdeps/x86/libc-start.h b/sysdeps/x86/libc-start.h +index e93da6ef3d..856230daeb 100644 +--- a/sysdeps/x86/libc-start.h ++++ b/sysdeps/x86/libc-start.h +@@ -19,7 +19,57 @@ + #ifndef SHARED + # define ARCH_SETUP_IREL() apply_irel () + # define ARCH_APPLY_IREL() +-# ifndef ARCH_SETUP_TLS +-# define ARCH_SETUP_TLS() __libc_setup_tls () ++# ifdef __CET__ ++/* Get CET features enabled in the static executable. */ ++ ++static inline unsigned int ++get_cet_feature (void) ++{ ++ /* Check if CET is supported and not disabled by tunables. */ ++ struct cpu_features *cpu_features ++ = (struct cpu_features *) __get_cpu_features (); ++ unsigned int cet_feature = 0; ++ if (CPU_FEATURE_USABLE_P (cpu_features, IBT)) ++ cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT; ++ if (CPU_FEATURE_USABLE_P (cpu_features, SHSTK)) ++ cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; ++ if (!cet_feature) ++ return cet_feature; ++ ++ struct link_map *main_map = _dl_get_dl_main_map (); ++ ++ /* Scan program headers backward to check PT_GNU_PROPERTY early for ++ x86 feature bits on static executable. */ ++ const ElfW(Phdr) *phdr = GL(dl_phdr); ++ const ElfW(Phdr) *ph; ++ for (ph = phdr + GL(dl_phnum); ph != phdr; ph--) ++ if (ph[-1].p_type == PT_GNU_PROPERTY) ++ { ++ _dl_process_pt_gnu_property (main_map, -1, &ph[-1]); ++ /* Enable IBT and SHSTK only if they are enabled on static ++ executable. */ ++ cet_feature &= (main_map->l_x86_feature_1_and ++ & (GNU_PROPERTY_X86_FEATURE_1_IBT ++ | GNU_PROPERTY_X86_FEATURE_1_SHSTK)); ++ /* Set GL(dl_x86_feature_1) to the enabled CET features. */ ++ GL(dl_x86_feature_1) = cet_feature; ++ break; ++ } ++ ++ return cet_feature; ++} ++ ++/* The function using this macro to enable shadow stack must not return ++ to avoid shadow stack underflow. */ ++# define ARCH_SETUP_TLS() \ ++ { \ ++ __libc_setup_tls (); \ ++ \ ++ unsigned int cet_feature = get_cet_feature (); \ ++ ENABLE_X86_CET (cet_feature); \ ++ _dl_cet_setup_features (cet_feature); \ ++ } ++# else ++# define ARCH_SETUP_TLS() __libc_setup_tls () + # endif + #endif /* !SHARED */ +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index 9ea2a70837..b4159880f3 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -29,6 +29,11 @@ + #include + #include + #include ++#ifdef __CET__ ++# include ++#else ++# define RTLD_START_ENABLE_X86_FEATURES ++#endif + + /* Return nonzero iff ELF header is compatible with the running host. */ + static inline int __attribute__ ((unused)) +@@ -144,13 +149,16 @@ _start:\n\ + _dl_start_user:\n\ + # Save the user entry point address in %r12.\n\ + movq %rax, %r12\n\ ++ # Save %rsp value in %r13.\n\ ++ movq %rsp, %r13\n\ ++"\ ++ RTLD_START_ENABLE_X86_FEATURES \ ++"\ + # Read the original argument count.\n\ + movq (%rsp), %rdx\n\ + # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\ + # argc -> rsi\n\ + movq %rdx, %rsi\n\ +- # Save %rsp value in %r13.\n\ +- movq %rsp, %r13\n\ + # And align stack for the _dl_init call. \n\ + andq $-16, %rsp\n\ + # _dl_loaded -> rdi\n\ +diff --git a/sysdeps/x86_64/x32/dl-machine.h b/sysdeps/x86_64/x32/dl-machine.h +index 648a11f926..d8598b3e9c 100644 +--- a/sysdeps/x86_64/x32/dl-machine.h ++++ b/sysdeps/x86_64/x32/dl-machine.h +@@ -45,13 +45,16 @@ _start:\n\ + _dl_start_user:\n\ + # Save the user entry point address in %r12.\n\ + movl %eax, %r12d\n\ ++ # Save %rsp value in %r13.\n\ ++ movl %esp, %r13d\n\ ++"\ ++ RTLD_START_ENABLE_X86_FEATURES \ ++"\ + # Read the original argument count.\n\ + movl (%rsp), %edx\n\ + # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\ + # argc -> rsi\n\ + movl %edx, %esi\n\ +- # Save %rsp value in %r13.\n\ +- movl %esp, %r13d\n\ + # And align stack for the _dl_init call.\n\ + and $-16, %esp\n\ + # _dl_loaded -> rdi\n\ +-- +2.40.1 + diff --git a/v2-0015-x86-cet-Check-feature_1-in-TCB-for-active-IBT-and.patch b/v2-0015-x86-cet-Check-feature_1-in-TCB-for-active-IBT-and.patch new file mode 100644 index 0000000..88ed83a --- /dev/null +++ b/v2-0015-x86-cet-Check-feature_1-in-TCB-for-active-IBT-and.patch @@ -0,0 +1,89 @@ +From 7b3c43e6b089eb7efefdbb32b99da6b1ab469151 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 11 Apr 2023 14:03:43 -0700 +Subject: [PATCH v2 15/15] x86/cet: Check feature_1 in TCB for active IBT and + SHSTK + +Initially, IBT and SHSTK are marked as active when CPU supports them +and CET are enabled in glibc. They can be disabled early by tunables +before relocation. Since after relocation, GLRO(dl_x86_cpu_features) +becomes read-only, we can't update GLRO(dl_x86_cpu_features) to mark +IBT and SHSTK as inactive. Instead, check the feature_1 field in TCB +to decide if IBT and SHST are active. +--- + sysdeps/x86/bits/platform/x86.h | 8 ++++++++ + sysdeps/x86/get-cpuid-feature-leaf.c | 11 ++++++++++- + sysdeps/x86/sys/platform/x86.h | 17 +++++++++++++++++ + 3 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/x86/bits/platform/x86.h b/sysdeps/x86/bits/platform/x86.h +index 6555f9b91d..c9b6ee1766 100644 +--- a/sysdeps/x86/bits/platform/x86.h ++++ b/sysdeps/x86/bits/platform/x86.h +@@ -326,3 +326,11 @@ enum + + x86_cpu_PTWRITE = x86_cpu_index_14_ecx_0_ebx + 4 + }; ++ ++/* Bits in the feature_1 field in TCB. */ ++ ++enum ++{ ++ x86_feature_1_ibt = 1U << 0, ++ x86_feature_1_shstk = 1U << 1 ++}; +diff --git a/sysdeps/x86/get-cpuid-feature-leaf.c b/sysdeps/x86/get-cpuid-feature-leaf.c +index 9317a6b494..f69936b31e 100644 +--- a/sysdeps/x86/get-cpuid-feature-leaf.c ++++ b/sysdeps/x86/get-cpuid-feature-leaf.c +@@ -15,9 +15,18 @@ + License along with the GNU C Library; if not, see + . */ + +- ++#include ++#include + #include + ++#ifdef __x86_64__ ++# ifdef __LP64__ ++_Static_assert (FEATURE_1_OFFSET == 72, "FEATURE_1_OFFSET != 72"); ++# else ++_Static_assert (FEATURE_1_OFFSET == 40, "FEATURE_1_OFFSET != 40"); ++# endif ++#endif ++ + const struct cpuid_feature * + __x86_get_cpuid_feature_leaf (unsigned int leaf) + { +diff --git a/sysdeps/x86/sys/platform/x86.h b/sysdeps/x86/sys/platform/x86.h +index 1ea2c5fc0b..89b1b16f22 100644 +--- a/sysdeps/x86/sys/platform/x86.h ++++ b/sysdeps/x86/sys/platform/x86.h +@@ -45,6 +45,23 @@ x86_cpu_present (unsigned int __index) + static __inline__ _Bool + x86_cpu_active (unsigned int __index) + { ++ if (__index == x86_cpu_IBT || __index == x86_cpu_SHSTK) ++ { ++#ifdef __x86_64__ ++ unsigned int __feature_1; ++# ifdef __LP64__ ++ __asm__ ("mov %%fs:72, %0" : "=r" (__feature_1)); ++# else ++ __asm__ ("mov %%fs:40, %0" : "=r" (__feature_1)); ++# endif ++ if (__index == x86_cpu_IBT) ++ return __feature_1 & x86_feature_1_ibt; ++ else ++ return __feature_1 & x86_feature_1_shstk; ++#else ++ return false; ++#endif ++ } + const struct cpuid_feature *__ptr = __x86_get_cpuid_feature_leaf + (__index / (8 * sizeof (unsigned int) * 4)); + unsigned int __reg +-- +2.40.1 +