Adds a X86_USER_IBT Kconfig option and "nouseribt" command-line option. Default disabled for now.
These prepare for userspace support for IBT (forward-edge control flow integrity protection). User IBT works even if kernel IBT is disabled. However, ibt=off also disables user IBT. Signed-off-by: Richard Patel <[email protected]> --- arch/x86/Kconfig | 17 +++++++++++++++++ arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/kernel/cet.c | 3 ++- arch/x86/kernel/cpu/common.c | 14 ++++++++++++-- tools/arch/x86/include/asm/cpufeatures.h | 1 + 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f3f7cb01d69d..12cc944b63c7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1901,6 +1901,23 @@ config X86_USER_SHADOW_STACK If unsure, say N. +config X86_USER_IBT + bool "X86 userspace indirect branch tracking" + depends on X86_64 + select X86_CET + help + Support Indirect Branch Tracking protection for userspace + applications. IBT is a hardware-supported coarse-grained + forward-edge Control Flow Integrity protection feature. + It enforces that all indirect calls must land on an ENDBR + instruction. Applications must be enabled to use it, and old + userspace does not get protection "for free". Enables the + PR_CFI_BRANCH_LANDING_PADS prctl CFI option. + + CPUs supporting IBT were first released in 2021. + + If unsure, say N. + config INTEL_TDX_HOST bool "Intel Trust Domain Extensions (TDX) host support" depends on CPU_SUP_INTEL diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 1d506e5d6f46..1825cbf864c0 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -516,6 +516,7 @@ * and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4k vCPUs */ +#define X86_FEATURE_USER_IBT (21*32+21) /* Indirect Branch Tracking for user mode applications */ /* * BUG word(s) diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c index 99444409c026..3ccf47e82da1 100644 --- a/arch/x86/kernel/cet.c +++ b/arch/x86/kernel/cet.c @@ -149,7 +149,8 @@ __setup("ibt=", ibt_setup); DEFINE_IDTENTRY_ERRORCODE(exc_control_protection) { if (user_mode(regs)) { - if (cpu_feature_enabled(X86_FEATURE_USER_SHSTK)) + if (cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || + cpu_feature_enabled(X86_FEATURE_USER_IBT)) do_user_cp_fault(regs, error_code); else do_unexpected_cp(regs, error_code); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a4268c47f2bc..2839edd92331 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -634,7 +634,7 @@ __noendbr void ibt_restore(u64 save) static __always_inline void setup_cet(struct cpuinfo_x86 *c) { - bool user_shstk, kernel_ibt; + bool user_shstk, kernel_ibt, user_ibt; if (!IS_ENABLED(CONFIG_X86_CET)) return; @@ -642,13 +642,19 @@ static __always_inline void setup_cet(struct cpuinfo_x86 *c) kernel_ibt = HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT); user_shstk = cpu_feature_enabled(X86_FEATURE_SHSTK) && IS_ENABLED(CONFIG_X86_USER_SHADOW_STACK); + /* User IBT only needs hardware IBT, not kernel-enabled IBT. */ + user_ibt = cpu_has(c, X86_FEATURE_IBT) && + IS_ENABLED(CONFIG_X86_USER_IBT); - if (!kernel_ibt && !user_shstk) + if (!kernel_ibt && !user_shstk && !user_ibt) return; if (user_shstk) set_cpu_cap(c, X86_FEATURE_USER_SHSTK); + if (user_ibt) + set_cpu_cap(c, X86_FEATURE_USER_IBT); + if (kernel_ibt) wrmsrq(MSR_IA32_S_CET, CET_ENDBR_EN); else @@ -666,6 +672,7 @@ static __always_inline void setup_cet(struct cpuinfo_x86 *c) __noendbr void cet_disable(void) { if (!(cpu_feature_enabled(X86_FEATURE_IBT) || + cpu_feature_enabled(X86_FEATURE_USER_IBT) || cpu_feature_enabled(X86_FEATURE_SHSTK))) return; @@ -1760,6 +1767,9 @@ static void __init cpu_parse_early_param(void) if (cmdline_find_option_bool(boot_command_line, "nousershstk")) setup_clear_cpu_cap(X86_FEATURE_USER_SHSTK); + if (cmdline_find_option_bool(boot_command_line, "nouseribt")) + setup_clear_cpu_cap(X86_FEATURE_USER_IBT); + /* Minimize the gap between FRED is available and available but disabled. */ arglen = cmdline_find_option(boot_command_line, "fred", arg, sizeof(arg)); if (arglen == 3 && !strncmp(arg, "off", 3)) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index 86d17b195e79..1cf22d27c7a1 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -515,6 +515,7 @@ * and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4k vCPUs */ +#define X86_FEATURE_USER_IBT (21*32+21) /* Indirect Branch Tracking for user mode applications */ /* * BUG word(s) -- 2.47.3

