From e16a8a6eb13584711bbc7111e6bcb467cbc09408 Mon Sep 17 00:00:00 2001 From: Farrah Chen Date: Mon, 24 Aug 2026 15:13:11 +0800 Subject: [PATCH] BM/cet: add signal/thread/legacy SHSTK and kernel IBT cases Add the missing CET shadow stack cases into BM/cet: - sig_stack.c: CET signal stack test, verify the signal-triggered function is protected by SHSTK (bare "a" access check and cp_test "s" violation). - cet_thread.c: SHSTK violation in a new thread should be #CP blocked. Accept upstream SEGV_CPERR(3) in addition to the legacy si_code 8|10 so the case works on mainline kernels. - glibc_shstk_test_legacy: build glibc_shstk_test.c without CET protection (NOCETFLAGS) and verify none of the violation params trigger #CP (no_cp). - test_shadow_stack.c: treat an EINVAL from UFFDIO_REGISTER on a shadow stack VMA as SKIP, since recent kernels reject userfaultfd registration of special VMAs. Kernel IBT b1/b2 cases: - cet_tests.sh: kmod_ibt_illegal triggers a kernel-space missing-ENDBR #CP; block the case unless the kernel is booted with ibt=warn (and block on ibt=off) to avoid crashing the host. - load_cet_driver block_tests with a clear message pointing at the required kernel-devel/headers when cet_ioctl.ko is missing. - cet_driver/Makefile: fail early with an actionable error when the kernel build dir is absent, and suppress the module's missing-prototype/declaration warnings on -Werror kernels. - cet_driver/cet_ioctl.h: guard CPUID_LEAF_XSTATE so it does not conflict with the kernel's own definition. Document the ibt=warn requirement in the tests list and README, and wire the new binaries into Makefile, CMakeLists.txt and .gitignore. Co-authored-by: GitHub Copilot Signed-off-by: Farrah Chen (cherry picked from commit 8e9069c323d408fcd75b4b61ee669b8fe3fc5425) --- BM/cet/.gitignore | 3 + BM/cet/CMakeLists.txt | 10 +- BM/cet/Makefile | 11 ++- BM/cet/README.md | 21 +++++ BM/cet/cet_driver/Makefile | 14 +++ BM/cet/cet_driver/cet_ioctl.h | 4 + BM/cet/cet_tests.sh | 13 ++- BM/cet/cet_thread.c | 154 ++++++++++++++++++++++++++++++ BM/cet/sig_stack.c | 173 ++++++++++++++++++++++++++++++++++ BM/cet/test_shadow_stack.c | 17 +++- BM/cet/tests | 25 ++++- 11 files changed, 437 insertions(+), 8 deletions(-) create mode 100644 BM/cet/cet_thread.c create mode 100644 BM/cet/sig_stack.c diff --git a/BM/cet/.gitignore b/BM/cet/.gitignore index a8b548e3..caaecc2a 100644 --- a/BM/cet/.gitignore +++ b/BM/cet/.gitignore @@ -1,5 +1,7 @@ cet_app +cet_thread glibc_shstk_test +glibc_shstk_test_legacy glibc_supported_shstk_test quick_test shstk_alloc @@ -8,5 +10,6 @@ shstk_cpu shstk_cpu_legacy shstk_huge_page shstk_unlock_test +sig_stack test_shadow_stack wrss diff --git a/BM/cet/CMakeLists.txt b/BM/cet/CMakeLists.txt index 23dfcb18..9e79ea13 100644 --- a/BM/cet/CMakeLists.txt +++ b/BM/cet/CMakeLists.txt @@ -24,7 +24,8 @@ execute_process(COMMAND gcc --version OUTPUT_VARIABLE GCC_VERSION) string(REGEX MATCH "([0-9]+)\\." GCC_VER_MAJOR ${GCC_VERSION}) if(GCC_VER_MAJOR GREATER_EQUAL 8) set(BIN shstk_alloc test_shadow_stack quick_test wrss shstk_huge_page - shstk_unlock_test shstk_cp cet_app glibc_shstk_test shstk_cpu shstk_cpu_legacy) + shstk_unlock_test shstk_cp cet_app glibc_shstk_test shstk_cpu shstk_cpu_legacy + glibc_shstk_test_legacy sig_stack cet_thread) else() message(WARNING "GCC version is less than 8, skipping build cet.") return() @@ -39,14 +40,17 @@ foreach(target ${BIN}) if(${target} STREQUAL "cet_app") add_executable(${target} cet_driver/cet_app.c) target_include_directories(${target} PRIVATE cet_driver) + elseif(${target} STREQUAL "glibc_shstk_test_legacy") + add_executable(${target} glibc_shstk_test.c) + target_compile_options(${target} PRIVATE ${NOCETFLAGS}) else() add_executable(${target} ${target}.c) - if(${target} MATCHES "quick_test|shstk_huge_page|glibc_shstk_test") + if(${target} MATCHES "quick_test|shstk_huge_page|glibc_shstk_test|sig_stack|cet_thread") target_compile_options(${target} PRIVATE ${CETFLAGS}) else() target_compile_options(${target} PRIVATE ${NOCETFLAGS}) endif() - if(${target} STREQUAL "test_shadow_stack") + if(${target} STREQUAL "test_shadow_stack" OR ${target} STREQUAL "cet_thread") target_link_libraries(${target} PRIVATE pthread) endif() endif() diff --git a/BM/cet/Makefile b/BM/cet/Makefile index 13d0e8b6..dee3e588 100644 --- a/BM/cet/Makefile +++ b/BM/cet/Makefile @@ -15,7 +15,7 @@ IS_KER_SRC = $(shell [ -d $(KER_SRC) ] && echo true) ifeq ($(GCC_GE_8),true) BIN := shstk_alloc test_shadow_stack quick_test wrss shstk_huge_page \ shstk_unlock_test shstk_cp cet_app glibc_shstk_test shstk_cpu \ - shstk_cpu_legacy + shstk_cpu_legacy glibc_shstk_test_legacy sig_stack cet_thread $(info GCC major version: ${GCC_VER_MAJOR}) else @@ -58,6 +58,15 @@ cet_app: glibc_shstk_test: glibc_shstk_test.c gcc $(CETFLAGS) $^ -o $@ +glibc_shstk_test_legacy: glibc_shstk_test.c + gcc $(NOCETFLAGS) $^ -o $@ + +sig_stack: sig_stack.c + gcc $(CETFLAGS) $^ -o $@ + +cet_thread: cet_thread.c + gcc -pthread $(CETFLAGS) $^ -o $@ + shstk_cpu: shstk_cpu.c gcc $(NOCETFLAGS) $^ -o $@ diff --git a/BM/cet/README.md b/BM/cet/README.md index f942f1a0..00f895fb 100644 --- a/BM/cet/README.md +++ b/BM/cet/README.md @@ -65,5 +65,26 @@ SHSTK enabled binary: 2. Write one incorrect value into shadow stack 3. The expected SISEGV should be received after ret instruction +## Kernel space IBT tests +The kernel IBT cases (`kmod_ibt_*`) load the `cet_driver` kernel module to +exercise Indirect Branch Tracking in kernel space. + +`kmod_ibt_illegal` intentionally performs an indirect jump to a target without +an `ENDBR` instruction, which triggers a kernel-space Control Protection (#CP) +fault. The kernel defaults to `ibt_fatal=true`, so the fault ends in `BUG()` +and crashes the machine. + +To run this case you MUST boot the kernel with `ibt=warn` on the cmdline. That +sets `ibt_fatal=false`, turning the fault into a recoverable `WARN` that logs +the expected `Missing ENDBR` message. Without `ibt=warn` the case is blocked +(reported as BLOCK) to avoid crashing the host; with `ibt=off` it is also +blocked because IBT is disabled. + +Add `ibt=warn` and reboot, for example: +``` +grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="ibt=warn" +reboot +``` + ## Expected result All test results should show pass, no fail. diff --git a/BM/cet/cet_driver/Makefile b/BM/cet/cet_driver/Makefile index 584ebae2..6ce76677 100644 --- a/BM/cet/cet_driver/Makefile +++ b/BM/cet/cet_driver/Makefile @@ -12,6 +12,14 @@ BIN := cet_ioctl all: $(BIN) cet_ioctl: + @if [ ! -d "$(KERNEL_SOURCE)" ]; then \ + echo "ERROR: kernel build dir $(KERNEL_SOURCE) not found."; \ + echo " Install the matching kernel-devel/kernel-headers package"; \ + echo " (e.g. 'dnf install kernel-devel-$(shell uname -r)' or"; \ + echo " 'apt install linux-headers-$(shell uname -r)') so the"; \ + echo " cet_ioctl module can be built, then re-run make."; \ + exit 1; \ + fi $(MAKE) -C $(KERNEL_SOURCE) M=$(PWD) modules clean: @@ -21,5 +29,11 @@ clean: # Otherwise KERNELRELEASE is defined; we've been invoked from the # kernel build system and can use its language. else + # The IBT/SHSTK helper functions (cet_ibt1, cet_shstk1, ...) are file-local + # but intentionally kept non-static so the compiler emits real stack frames + # and indirect jumps needed to trigger #CP. Suppress the missing prototype/ + # declaration warnings so the module still builds on kernels configured with + # -Werror for them. + ccflags-y += -Wno-missing-prototypes -Wno-missing-declarations obj-m := cet_ioctl.o endif diff --git a/BM/cet/cet_driver/cet_ioctl.h b/BM/cet/cet_driver/cet_ioctl.h index 32d623be..ab9d4f80 100644 --- a/BM/cet/cet_driver/cet_ioctl.h +++ b/BM/cet/cet_driver/cet_ioctl.h @@ -26,8 +26,12 @@ }) #endif +#ifndef CPUID_LEAF_XSTATE #define CPUID_LEAF_XSTATE 0xd +#endif +#ifndef CPUID_SUBLEAF_XSTATE_USER #define CPUID_SUBLEAF_XSTATE_USER 0x0 +#endif #define MSR_IA32_PL3_SSP 0x000006a7 /* user shadow stack pointer */ diff --git a/BM/cet/cet_tests.sh b/BM/cet/cet_tests.sh index 2e12c778..28382e8e 100755 --- a/BM/cet/cet_tests.sh +++ b/BM/cet/cet_tests.sh @@ -46,7 +46,7 @@ load_cet_driver() { pat=$(pwd) echo "pat:$pat" - [[ -e "$KO_FILE" ]] || block_test "No $TEST_MOD_KO exist, please make it first" + [[ -e "$KO_FILE" ]] || block_test "No $TEST_MOD_KO exist; build it first with 'make' in cet/cet_driver (requires kernel-devel/headers for $(uname -r))" mod_info=$(modinfo "$KO_FILE") ker_ver=$(uname -r) if [[ "$mod_info" == *"$ker_ver"* ]]; then @@ -251,6 +251,17 @@ cet_tests() { cet_dmesg_check "$bin_file" "$PARM" "$KEYWORD" "$CONTAIN" ;; kmod_ibt_illegal) + # cet_ibt1() in the driver deliberately does an indirect jump to a + # target without ENDBR, triggering a kernel-space #CP. With + # CONFIG_X86_KERNEL_IBT the kernel defaults to ibt_fatal=true, so the + # fault ends in BUG() and crashes the machine. Only ibt=warn + # (ibt_fatal=false) turns it into a recoverable WARN that logs the + # expected "Missing ENDBR". Guard here to avoid crashing the host. + if grep -qw "ibt=off" /proc/cmdline; then + block_test "Kernel IBT is disabled via ibt=off; kmod_ibt_illegal needs IBT enabled" + fi + grep -qw "ibt=warn" /proc/cmdline || \ + block_test "kmod_ibt_illegal triggers a fatal kernel #CP (BUG) without ibt=warn; boot with ibt=warn to run it safely" load_cet_driver cet_dmesg_check "$bin_file" "$PARM" "$KEYWORD" "$CONTAIN" ;; diff --git a/BM/cet/cet_thread.c b/BM/cet/cet_thread.c new file mode 100644 index 00000000..e1d34bdb --- /dev/null +++ b/BM/cet/cet_thread.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Intel Corporation. +/* + * cet_thread.c: + * + * Author: Pengfei Xu + * + * - CET(Control-flow Enforcement Technology) verification in threads. + * - Parameter "s": test shadow stack violation in a new thread, which + * should be #CP blocked and get SIGSEGV. + * - Parameter "i": test indirect branch tracking violation in a new + * thread, which should be #CP blocked and get SIGSEGV. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Upstream kernel reports control protection fault as SEGV_CPERR. */ +#ifndef SEGV_CPERR +#define SEGV_CPERR 3 +#endif + +void printids(const char *s) +{ + pid_t pid; + pthread_t tid; + + pid = getpid(); + tid = pthread_self(); + printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid, + (unsigned int)tid, (unsigned int)tid); +} + +int hack(void) +{ + printf("%s function, which should be #cp blocked\n", __func__); + sleep(1); + return 1; +} + +void *thr_shstk(void *arg) +{ + unsigned long *p; + + printids("new shstk thread: "); + #ifdef __x86_64__ + asm("movq %%rbp,%0" : "=r"(p)); + #else + asm("mov %%ebp,%0" : "=r"(p)); + #endif + + *(p + 1) = (unsigned long)hack; + return NULL; +} + +void *thr_ibt(void *arg) +{ + printids("new ibt thread: "); + #ifdef __x86_64__ + asm volatile("leaq 1f, %rax"); + asm volatile("jmpq *%rax"); + #else + asm volatile("lea 1f, %eax"); + asm volatile("jmp *%eax"); + #endif + asm volatile("1:"); + printf("ibt test, which should be #cp blocked\n"); + return NULL; +} + +void segv_handler(int signum, siginfo_t *si, void *uc) +{ + int exp_code = 8, new_code = 10; + + printf("si_signo:%d\n", si->si_signo); + printf("si_errno:%d\n", si->si_errno); + printf("si_code:%d\n", si->si_code); + if (si->si_code == exp_code || si->si_code == new_code || + si->si_code == SEGV_CPERR) + printf("Got SIGSEGV(11) and si_code(%d|%d|%d) as expected\n", + exp_code, new_code, SEGV_CPERR); + else { + printf("si_code error, actual:%d, expect:%d|%d|%d.\n", + si->si_code, exp_code, new_code, SEGV_CPERR); + exit(1); + } + exit(0); +} + +void usage(void) +{ + printf("Usage: [s][i]\n"); + printf("s: Test shadow stack in thread\n"); + printf("i: Test ibt in thread\n"); +} + +int main(int argc, char *argv[]) +{ + int err, r; + pthread_t ntid; + struct sigaction sa; + char parm; + + if (argc == 1) { + usage(); + exit(2); + } else { + if (sscanf(argv[1], "%c", &parm) != 1) + return -EINVAL; + printf("parm:%c\n", parm); + } + + r = sigemptyset(&sa.sa_mask); + if (r) { + printf("Init empty signal failed\n"); + return -1; + } + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = segv_handler; + r = sigaction(SIGSEGV, &sa, NULL); + if (r) { + printf("Could not handle SIGSEGV(11)\n"); + return -1; + } + + switch (parm) { + case 's': + err = pthread_create(&ntid, NULL, thr_shstk, NULL); + if (err != 0) { + printf("can't create thr_shstk: %s\n", strerror(err)); + exit(1); + } + break; + case 'i': + err = pthread_create(&ntid, NULL, thr_ibt, NULL); + if (err != 0) { + printf("can't create thr_ibt: %s\n", strerror(err)); + exit(1); + } + break; + default: + usage(); + exit(2); + } + printids("process created thread:"); + sleep(2); + pthread_join(ntid, NULL); + return EXIT_FAILURE; +} diff --git a/BM/cet/sig_stack.c b/BM/cet/sig_stack.c new file mode 100644 index 00000000..79c8ace2 --- /dev/null +++ b/BM/cet/sig_stack.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Intel Corporation. +/* + * sig_stack.c: + * + * Author: Pengfei Xu + * + * - CET(Control-flow Enforcement Technology) signal stack test. + * - Verify the signal trigger function could be protected by CET. + * - Parameter "a": signal stack access cet stack check test. + * - Parameter "s": signal stack access and shstk violation test, which + * should be #CP blocked. + */ + +#include +#include +#include +#include +#include + +void sigaction_handler(int signum, siginfo_t *info, void *ptr) +{ + unsigned long *p_rbp, *addr_ssp; + + asm volatile ("rdsspq %rbx"); + asm("movq %%rbx,%0" : "=r"(addr_ssp)); + asm("movq %%rbp,%0" : "=r"(p_rbp)); + + printf("%s():rbp=%p, p_rbp=%p, *(p_rbp+1):%lx\n", + __func__, __builtin_frame_address(0), p_rbp, *(p_rbp + 1)); + printf("%s():__builtin_return_address=%p\n", + __func__, __builtin_return_address(0)); + printf("%s(): ssp:%p, *ssp:%lx\n", + __func__, addr_ssp, *addr_ssp); + printf("ssp+1:%p, *(ssp+1):%lx\nssp+2:%p, *(ssp+2):%lx\n", + addr_ssp + 1, *(addr_ssp + 1), addr_ssp + 2, *(addr_ssp + 2)); + if (*(p_rbp + 1) != *addr_ssp) { + printf("SIGUSR1 trigger handler, *(rbp+1):%lx not equal to *ssp:%lx\n", + *(p_rbp + 1), *addr_ssp); + exit(1); + } +} + +int signal_access_func(void) +{ + stack_t ss; + struct sigaction sigact; + unsigned long *addr_rbp, *addr_ssp; + + ss.ss_sp = malloc(SIGSTKSZ); + ss.ss_flags = 0; + ss.ss_size = SIGSTKSZ; + + addr_rbp = __builtin_frame_address(0); + addr_ssp = (unsigned long *)_get_ssp(); + + printf("sigaltstack ss.ss_sp:%p\n", (void *)ss.ss_sp); + printf("%s: rbp:%p, *(rbp):%lx, *(rbp+1):%lx\n", + __func__, addr_rbp, *addr_rbp, *(addr_rbp + 1)); + printf("%s: ssp:%p, *ssp:%lx\n", + __func__, addr_ssp, *addr_ssp); + + sigact.sa_sigaction = sigaction_handler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_ONSTACK; + sigaction(SIGUSR1, &sigact, NULL); + raise(SIGUSR1); + + printf("After signal SIGUSR1:rbp=%p\n", __builtin_frame_address(0)); + return 0; +} + +int hack(void) +{ + printf("Access %s function, Which should be #cp blocked\n", __func__); + exit(1); +} + +void shstk_violation_handler(int signum, siginfo_t *si, void *uc) +{ + int exp_sig = 12; + unsigned long *p_rbp, *addr_ssp; + + addr_ssp = (unsigned long *)_get_ssp(); + printf("signal SIGUSR2(#12) received:\nsi_signo:%d\n", si->si_signo); + printf("si_errno:%d\n", si->si_errno); + printf("si_code:%d\n", si->si_code); + printf("%s: ssp:%p, *ssp:%lx\n", + __func__, addr_ssp, *addr_ssp); + printf("ssp+1:%p, *(ssp+1):%lx\nssp+2:%p, *(ssp+2):%lx\n", + addr_ssp + 1, *(addr_ssp + 1), addr_ssp + 2, *(addr_ssp + 2)); + + if (si->si_signo != exp_sig) { + printf("si_signo error, actual:%d, expect:%d.\n", + si->si_signo, exp_sig); + exit(1); + } + + p_rbp = __builtin_frame_address(0); + *(p_rbp + 1) = (unsigned long)hack; +} + +int signal_shstk_violation(void) +{ + int result; + struct sigaction sa; + unsigned long *addr_ssp; + + asm volatile ("rdsspq %rbx"); + asm("movq %%rbx,%0" : "=r"(addr_ssp)); + printf("%s: ssp:%p, *ssp:%lx\n", + __func__, addr_ssp, *addr_ssp); + result = sigemptyset(&sa.sa_mask); + if (result) { + printf("Init empty sa signal failed\n"); + return 2; + } + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = shstk_violation_handler; + result = sigaction(SIGUSR2, &sa, NULL); + if (result) { + printf("Could not handle SIGUSR2(12)\n"); + return 2; + } + raise(SIGUSR2); + + return 0; +} + +void usage(void) +{ + printf("Usage: [a][s]\n"); + printf(" a: signal stack access cet stack check test\n"); + printf(" s: signal stack access and shstk violation test\n"); +} + +int main(int argc, char **argv) +{ + struct sigaction sa; + int result; + char parm; + + result = sigemptyset(&sa.sa_mask); + if (result) { + printf("Init empty sa signal failed\n"); + return 2; + } + + if (argc == 1) { + usage(); + exit(2); + } else { + if (sscanf(argv[1], "%c", &parm) != 1) { + printf("Invalid parameter:%s\n", argv[1]); + exit(2); + } + printf("parm:%c\n", parm); + } + + switch (parm) { + case 'a': + signal_access_func(); + break; + case 's': + signal_shstk_violation(); + break; + default: + usage(); + exit(2); + } + + return 0; +} diff --git a/BM/cet/test_shadow_stack.c b/BM/cet/test_shadow_stack.c index 9d8a3d58..0530f55a 100644 --- a/BM/cet/test_shadow_stack.c +++ b/BM/cet/test_shadow_stack.c @@ -537,8 +537,23 @@ int test_userfaultfd(void) uffdio_register.range.start = (__u64)shstk_ptr; uffdio_register.range.len = 4096; uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; - if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) { + /* + * Since Linux v7.2-rc5 (commit 3c58f641e813 "userfaultfd: + * prevent registration of special VMAs"), the kernel rejects + * userfaultfd registration on VM_SHADOW_STACK VMAs with + * -EINVAL to close a CET Shadow Stack bypass. Treat this as + * an expected SKIP rather than a test failure. + */ + if (errno == EINVAL) { + printf("[SKIP]\tUserfaultfd registration on shadow stack rejected by kernel (expected since v7.2-rc5 commit 3c58f641e813).\n"); + free_shstk(shstk_ptr); + close(uffd); + signal(SIGSEGV, SIG_DFL); + return 0; + } goto err; + } if (pthread_create(&thread, NULL, &uffd_thread, &uffd)) goto err; diff --git a/BM/cet/tests b/BM/cet/tests index 918daefe..39327a45 100644 --- a/BM/cet/tests +++ b/BM/cet/tests @@ -24,12 +24,33 @@ cet_tests.sh -t no_cp -n glibc_shstk_test -k "control protection" -p s1 cet_tests.sh -t no_cp -n glibc_shstk_test -k "control protection" -p s3 cet_tests.sh -t no_cp -n glibc_shstk_test -k "control protection" -p buf2 cet_tests.sh -t cet_ssp -n glibc_shstk_test -p ssp +# Legacy binary(without CET protection) should not trigger #CP on any param +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p s1 +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p s2 +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p s3 +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p sl1 +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p sr +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p sn +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p buf1 +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p buf2 +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p snc +cet_tests.sh -t no_cp -n glibc_shstk_test_legacy -k "control protection" -p sc +# CET SHSTK signal stack tests +sig_stack a +cet_tests.sh -t cp_test -n sig_stack -k "control protection" -p s +# CET SHSTK violation in a new thread should be #CP blocked +cet_thread s # CET user space SHSTK enable/disable performance tests on random cpu cet_tests.sh -t specific_cpu_perf -n shstk_cpu -p "random" # CET user space SHSTK enable/disable performance tests on each cpu cet_tests.sh -t all_cpu_perf -n shstk_cpu # Kernel space IBT tests +# NOTE: kmod_ibt_illegal deliberately triggers a kernel-space missing-ENDBR #CP. +# The kernel defaults to ibt_fatal=true, so without "ibt=warn" on the kernel +# cmdline the fault ends in BUG() and crashes the machine. Boot with "ibt=warn" +# to make it a recoverable WARN that logs "Missing ENDBR"; otherwise the case is +# blocked to protect the host. general_test.sh -t dmesg -p "contain" -k "Indirect Branch Tracking enabled" cet_tests.sh -t kmod_ibt_msr -#cet_tests.sh -t kmod_ibt_illegal -n cet_app -p "b1" -k "Missing ENDBR" -#cet_tests.sh -t kmod_ibt_legal -n cet_app -p "b2" -k "Missing ENDBR" +cet_tests.sh -t kmod_ibt_illegal -n cet_app -p "b1" -k "Missing ENDBR" +cet_tests.sh -t kmod_ibt_legal -n cet_app -p "b2" -k "Missing ENDBR"