Commit fa1202ef authored by Thomas Gleixner's avatar Thomas Gleixner

x86/speculation: Add command line control for indirect branch speculation

Add command line control for user space indirect branch speculation
mitigations. The new option is: spectre_v2_user=

The initial options are:

    -  on:   Unconditionally enabled
    - off:   Unconditionally disabled
    -auto:   Kernel selects mitigation (default off for now)

When the spectre_v2= command line argument is either 'on' or 'off' this
implies that the application to application control follows that state even
if a contradicting spectre_v2_user= argument is supplied.
Originally-by: default avatarTim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarIngo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: David Woodhouse <dwmw@amazon.co.uk>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Casey Schaufler <casey.schaufler@intel.com>
Cc: Asit Mallick <asit.k.mallick@intel.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Jon Masters <jcm@redhat.com>
Cc: Waiman Long <longman9394@gmail.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Dave Stewart <david.c.stewart@intel.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/20181125185005.082720373@linutronix.de
parent 495d470e
...@@ -4194,9 +4194,13 @@ ...@@ -4194,9 +4194,13 @@
spectre_v2= [X86] Control mitigation of Spectre variant 2 spectre_v2= [X86] Control mitigation of Spectre variant 2
(indirect branch speculation) vulnerability. (indirect branch speculation) vulnerability.
The default operation protects the kernel from
user space attacks.
on - unconditionally enable on - unconditionally enable, implies
off - unconditionally disable spectre_v2_user=on
off - unconditionally disable, implies
spectre_v2_user=off
auto - kernel detects whether your CPU model is auto - kernel detects whether your CPU model is
vulnerable vulnerable
...@@ -4206,6 +4210,12 @@ ...@@ -4206,6 +4210,12 @@
CONFIG_RETPOLINE configuration option, and the CONFIG_RETPOLINE configuration option, and the
compiler with which the kernel was built. compiler with which the kernel was built.
Selecting 'on' will also enable the mitigation
against user space to user space task attacks.
Selecting 'off' will disable both the kernel and
the user space protections.
Specific mitigations can also be selected manually: Specific mitigations can also be selected manually:
retpoline - replace indirect branches retpoline - replace indirect branches
...@@ -4215,6 +4225,24 @@ ...@@ -4215,6 +4225,24 @@
Not specifying this option is equivalent to Not specifying this option is equivalent to
spectre_v2=auto. spectre_v2=auto.
spectre_v2_user=
[X86] Control mitigation of Spectre variant 2
(indirect branch speculation) vulnerability between
user space tasks
on - Unconditionally enable mitigations. Is
enforced by spectre_v2=on
off - Unconditionally disable mitigations. Is
enforced by spectre_v2=off
auto - Kernel selects the mitigation depending on
the available CPU features and vulnerability.
Default is off.
Not specifying this option is equivalent to
spectre_v2_user=auto.
spec_store_bypass_disable= spec_store_bypass_disable=
[HW] Control Speculative Store Bypass (SSB) Disable mitigation [HW] Control Speculative Store Bypass (SSB) Disable mitigation
(Speculative Store Bypass vulnerability) (Speculative Store Bypass vulnerability)
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#ifndef _ASM_X86_NOSPEC_BRANCH_H_ #ifndef _ASM_X86_NOSPEC_BRANCH_H_
#define _ASM_X86_NOSPEC_BRANCH_H_ #define _ASM_X86_NOSPEC_BRANCH_H_
#include <linux/static_key.h>
#include <asm/alternative.h> #include <asm/alternative.h>
#include <asm/alternative-asm.h> #include <asm/alternative-asm.h>
#include <asm/cpufeatures.h> #include <asm/cpufeatures.h>
...@@ -226,6 +228,12 @@ enum spectre_v2_mitigation { ...@@ -226,6 +228,12 @@ enum spectre_v2_mitigation {
SPECTRE_V2_IBRS_ENHANCED, SPECTRE_V2_IBRS_ENHANCED,
}; };
/* The indirect branch speculation control variants */
enum spectre_v2_user_mitigation {
SPECTRE_V2_USER_NONE,
SPECTRE_V2_USER_STRICT,
};
/* The Speculative Store Bypass disable variants */ /* The Speculative Store Bypass disable variants */
enum ssb_mitigation { enum ssb_mitigation {
SPEC_STORE_BYPASS_NONE, SPEC_STORE_BYPASS_NONE,
...@@ -303,6 +311,8 @@ do { \ ...@@ -303,6 +311,8 @@ do { \
preempt_enable(); \ preempt_enable(); \
} while (0) } while (0)
DECLARE_STATIC_KEY_FALSE(switch_to_cond_stibp);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
/* /*
......
...@@ -54,6 +54,9 @@ static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS; ...@@ -54,6 +54,9 @@ static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS;
u64 __ro_after_init x86_amd_ls_cfg_base; u64 __ro_after_init x86_amd_ls_cfg_base;
u64 __ro_after_init x86_amd_ls_cfg_ssbd_mask; u64 __ro_after_init x86_amd_ls_cfg_ssbd_mask;
/* Control conditional STIPB in switch_to() */
DEFINE_STATIC_KEY_FALSE(switch_to_cond_stibp);
void __init check_bugs(void) void __init check_bugs(void)
{ {
identify_boot_cpu(); identify_boot_cpu();
...@@ -199,6 +202,9 @@ static void x86_amd_ssb_disable(void) ...@@ -199,6 +202,9 @@ static void x86_amd_ssb_disable(void)
static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
SPECTRE_V2_NONE; SPECTRE_V2_NONE;
static enum spectre_v2_user_mitigation spectre_v2_user __ro_after_init =
SPECTRE_V2_USER_NONE;
#ifdef RETPOLINE #ifdef RETPOLINE
static bool spectre_v2_bad_module; static bool spectre_v2_bad_module;
...@@ -237,6 +243,104 @@ enum spectre_v2_mitigation_cmd { ...@@ -237,6 +243,104 @@ enum spectre_v2_mitigation_cmd {
SPECTRE_V2_CMD_RETPOLINE_AMD, SPECTRE_V2_CMD_RETPOLINE_AMD,
}; };
enum spectre_v2_user_cmd {
SPECTRE_V2_USER_CMD_NONE,
SPECTRE_V2_USER_CMD_AUTO,
SPECTRE_V2_USER_CMD_FORCE,
};
static const char * const spectre_v2_user_strings[] = {
[SPECTRE_V2_USER_NONE] = "User space: Vulnerable",
[SPECTRE_V2_USER_STRICT] = "User space: Mitigation: STIBP protection",
};
static const struct {
const char *option;
enum spectre_v2_user_cmd cmd;
bool secure;
} v2_user_options[] __initdata = {
{ "auto", SPECTRE_V2_USER_CMD_AUTO, false },
{ "off", SPECTRE_V2_USER_CMD_NONE, false },
{ "on", SPECTRE_V2_USER_CMD_FORCE, true },
};
static void __init spec_v2_user_print_cond(const char *reason, bool secure)
{
if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2) != secure)
pr_info("spectre_v2_user=%s forced on command line.\n", reason);
}
static enum spectre_v2_user_cmd __init
spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
{
char arg[20];
int ret, i;
switch (v2_cmd) {
case SPECTRE_V2_CMD_NONE:
return SPECTRE_V2_USER_CMD_NONE;
case SPECTRE_V2_CMD_FORCE:
return SPECTRE_V2_USER_CMD_FORCE;
default:
break;
}
ret = cmdline_find_option(boot_command_line, "spectre_v2_user",
arg, sizeof(arg));
if (ret < 0)
return SPECTRE_V2_USER_CMD_AUTO;
for (i = 0; i < ARRAY_SIZE(v2_user_options); i++) {
if (match_option(arg, ret, v2_user_options[i].option)) {
spec_v2_user_print_cond(v2_user_options[i].option,
v2_user_options[i].secure);
return v2_user_options[i].cmd;
}
}
pr_err("Unknown user space protection option (%s). Switching to AUTO select\n", arg);
return SPECTRE_V2_USER_CMD_AUTO;
}
static void __init
spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
{
enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
bool smt_possible = IS_ENABLED(CONFIG_SMP);
if (!boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_STIBP))
return;
if (cpu_smt_control == CPU_SMT_FORCE_DISABLED ||
cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
smt_possible = false;
switch (spectre_v2_parse_user_cmdline(v2_cmd)) {
case SPECTRE_V2_USER_CMD_AUTO:
case SPECTRE_V2_USER_CMD_NONE:
goto set_mode;
case SPECTRE_V2_USER_CMD_FORCE:
mode = SPECTRE_V2_USER_STRICT;
break;
}
/* Initialize Indirect Branch Prediction Barrier */
if (boot_cpu_has(X86_FEATURE_IBPB)) {
setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n");
}
/* If enhanced IBRS is enabled no STIPB required */
if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
return;
set_mode:
spectre_v2_user = mode;
/* Only print the STIBP mode when SMT possible */
if (smt_possible)
pr_info("%s\n", spectre_v2_user_strings[mode]);
}
static const char * const spectre_v2_strings[] = { static const char * const spectre_v2_strings[] = {
[SPECTRE_V2_NONE] = "Vulnerable", [SPECTRE_V2_NONE] = "Vulnerable",
[SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline",
...@@ -385,12 +489,6 @@ static void __init spectre_v2_select_mitigation(void) ...@@ -385,12 +489,6 @@ static void __init spectre_v2_select_mitigation(void)
setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n"); pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
/* Initialize Indirect Branch Prediction Barrier if supported */
if (boot_cpu_has(X86_FEATURE_IBPB)) {
setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n");
}
/* /*
* Retpoline means the kernel is safe because it has no indirect * Retpoline means the kernel is safe because it has no indirect
* branches. Enhanced IBRS protects firmware too, so, enable restricted * branches. Enhanced IBRS protects firmware too, so, enable restricted
...@@ -407,23 +505,21 @@ static void __init spectre_v2_select_mitigation(void) ...@@ -407,23 +505,21 @@ static void __init spectre_v2_select_mitigation(void)
pr_info("Enabling Restricted Speculation for firmware calls\n"); pr_info("Enabling Restricted Speculation for firmware calls\n");
} }
/* Set up IBPB and STIBP depending on the general spectre V2 command */
spectre_v2_user_select_mitigation(cmd);
/* Enable STIBP if appropriate */ /* Enable STIBP if appropriate */
arch_smt_update(); arch_smt_update();
} }
static bool stibp_needed(void) static bool stibp_needed(void)
{ {
if (spectre_v2_enabled == SPECTRE_V2_NONE)
return false;
/* Enhanced IBRS makes using STIBP unnecessary. */ /* Enhanced IBRS makes using STIBP unnecessary. */
if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
return false; return false;
if (!boot_cpu_has(X86_FEATURE_STIBP)) /* Check for strict user mitigation mode */
return false; return spectre_v2_user == SPECTRE_V2_USER_STRICT;
return true;
} }
static void update_stibp_msr(void *info) static void update_stibp_msr(void *info)
...@@ -844,10 +940,13 @@ static char *stibp_state(void) ...@@ -844,10 +940,13 @@ static char *stibp_state(void)
if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
return ""; return "";
if (x86_spec_ctrl_base & SPEC_CTRL_STIBP) switch (spectre_v2_user) {
return ", STIBP"; case SPECTRE_V2_USER_NONE:
else return ", STIBP: disabled";
return ""; case SPECTRE_V2_USER_STRICT:
return ", STIBP: forced";
}
return "";
} }
static char *ibpb_state(void) static char *ibpb_state(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment