From dffd3e21c3de9fe426810ac891409a173e00ad02 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Mon, 18 Dec 2017 10:54:59 -0800 Subject: [PATCH] *Scaffolding* x86/spec_ctrl: Add sysctl knobs to enable/disable SPEC_CTRL feature 1. At boot time noibrs kernel boot parameter will disable IBRS usage noibpb kernel boot parameter will disable IBPB usage Otherwise if the above parameters are not specified, the system will enable ibrs and ibpb usage if the cpu supports it. Orabug: 27344012 CVE: CVE-2017-5715 Signed-off-by: Konrad Rzeszutek Wilk [*Scaffolding*:This backport lacks a lot. It is only put it on so that the later patches compiled _and_ can be tested to run. It is meant to be removed once the full set of patches are all good. Aka scaffolding.] Reviewed-by: John Haxby Signed-off-by: Kirtikar Kashyap --- Documentation/kernel-parameters.txt | 10 ++++ arch/x86/include/asm/spec_ctrl.h | 2 + arch/x86/kernel/cpu/intel.c | 4 +- include/linux/smp.h | 86 +++++++++++++++++++++++++++++ kernel/smp.c | 37 +++++++++++++ 5 files changed, 138 insertions(+), 1 deletion(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 198bcf10d93b..ad6bb62c209e 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2354,6 +2354,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noexec=on: enable non-executable mappings (default) noexec=off: disable non-executable mappings + noibrs [X86] + Don't use indirect branch restricted speculation (IBRS) + feature when running in secure environment, + to avoid performance overhead. + + noibpb [X86] + Don't use indirect branch prediction barrier (IBPB) + feature when running in secure environment, + to avoid performance overhead. + nosmap [X86] Disable SMAP (Supervisor Mode Access Prevention) even if it is supported by processor. diff --git a/arch/x86/include/asm/spec_ctrl.h b/arch/x86/include/asm/spec_ctrl.h index 3080f33fbd08..1d313ff9799b 100644 --- a/arch/x86/include/asm/spec_ctrl.h +++ b/arch/x86/include/asm/spec_ctrl.h @@ -8,6 +8,8 @@ #ifdef __ASSEMBLY__ +.extern use_ibrs + #define __ASM_ENABLE_IBRS \ pushq %rax; \ pushq %rcx; \ diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 4257d6a7db7d..bcb5303de902 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -494,8 +494,10 @@ static void init_intel(struct cpuinfo_x86 *c) } } - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { printk_once(KERN_INFO "FEATURE SPEC_CTRL Present\n"); + set_ibrs_supported(); + } else printk_once(KERN_INFO "FEATURE SPEC_CTRL Not Present\n"); } diff --git a/include/linux/smp.h b/include/linux/smp.h index c4414074bd88..c340e38a6656 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -50,6 +50,92 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), int smp_call_function_single_async(int cpu, struct call_single_data *csd); +#ifdef CONFIG_X86 +/* indicate usage of IBRS to control execution speculation */ +extern int use_ibrs; +extern u32 sysctl_ibrs_enabled; +#define ibrs_supported (use_ibrs & 0x2) +#define ibrs_disabled (use_ibrs & 0x4) +static inline void set_ibrs_inuse(void) +{ + if (ibrs_supported) + use_ibrs |= 0x1; +} +static inline void clear_ibrs_inuse(void) +{ + use_ibrs &= ~0x1; +} +static inline int check_ibrs_inuse(void) +{ + if (use_ibrs & 0x1) + return 1; + else + /* rmb to prevent wrong speculation for security */ + rmb(); + return 0; +} +static inline void set_ibrs_supported(void) +{ + use_ibrs |= 0x2; + if (!ibrs_disabled) + set_ibrs_inuse(); +} +static inline void set_ibrs_disabled(void) +{ + use_ibrs |= 0x4; + if (check_ibrs_inuse()) + clear_ibrs_inuse(); +} +static inline void clear_ibrs_disabled(void) +{ + use_ibrs &= ~0x4; + set_ibrs_inuse(); +} +#define ibrs_inuse (check_ibrs_inuse()) + +/* indicate usage of IBPB to control execution speculation */ +extern int use_ibpb; +extern u32 sysctl_ibpb_enabled; +#define ibpb_supported (use_ibpb & 0x2) +#define ibpb_disabled (use_ibpb & 0x4) +static inline void set_ibpb_inuse(void) +{ + if (ibpb_supported) + use_ibpb |= 0x1; +} +static inline void clear_ibpb_inuse(void) +{ + use_ibpb &= ~0x1; +} +static inline int check_ibpb_inuse(void) +{ + if (use_ibpb & 0x1) + return 1; + else + /* rmb to prevent wrong speculation for security */ + rmb(); + return 0; +} +static inline void set_ibpb_supported(void) +{ + use_ibpb |= 0x2; + if (!ibpb_disabled) + set_ibpb_inuse(); +} +static inline void set_ibpb_disabled(void) +{ + use_ibpb |= 0x4; + if (check_ibpb_inuse()) + clear_ibpb_inuse(); +} +static inline void clear_ibpb_disabled(void) +{ + use_ibpb &= ~0x4; + set_ibpb_inuse(); +} +#define ibpb_inuse (check_ibpb_inuse()) +#endif + #ifdef CONFIG_SMP #include diff --git a/kernel/smp.c b/kernel/smp.c index 07854477c164..8db57e98cd2d 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -499,6 +499,24 @@ EXPORT_SYMBOL(smp_call_function); unsigned int setup_max_cpus = NR_CPUS; EXPORT_SYMBOL(setup_max_cpus); +/* + * use IBRS + * bit 0 = indicate if ibrs is currently in use + * bit 1 = indicate if system supports ibrs + * bit 2 = indicate if admin disables ibrs +*/ + +int use_ibrs; +EXPORT_SYMBOL(use_ibrs); + +/* + * use IBRS + * bit 0 = indicate if ibpb is currently in use + * bit 1 = indicate if system supports ibpb + * bit 2 = indicate if admin disables ibpb +*/ +int use_ibpb; +EXPORT_SYMBOL(use_ibpb); /* * Setup routine for controlling SMP activation @@ -523,6 +541,25 @@ static int __init nosmp(char *str) early_param("nosmp", nosmp); +static int __init noibrs(char *str) +{ + set_ibrs_disabled(); + + return 0; +} + +early_param("noibrs", noibrs); + +static int __init noibpb(char *str) +{ + set_ibpb_disabled(); + + return 0; +} + +early_param("noibpb", noibpb); + + /* this is hard limit */ static int __init nrcpus(char *str) { -- 2.50.1