x86/speculation: Add spectre_v2=ibrs option to support Kernel IBRS
commit 7c693f54c873691a4b7da05c7e0f74e67745d144 upstream. Extend spectre_v2= boot option with Kernel IBRS. [jpoimboe: no STIBP with IBRS] Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Borislav Petkov <bp@suse.de> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
6d7e13ccc4
commit
dabc2a1b40
@@ -5026,6 +5026,7 @@
|
|||||||
eibrs - enhanced IBRS
|
eibrs - enhanced IBRS
|
||||||
eibrs,retpoline - enhanced IBRS + Retpolines
|
eibrs,retpoline - enhanced IBRS + Retpolines
|
||||||
eibrs,lfence - enhanced IBRS + LFENCE
|
eibrs,lfence - enhanced IBRS + LFENCE
|
||||||
|
ibrs - use IBRS to protect kernel
|
||||||
|
|
||||||
Not specifying this option is equivalent to
|
Not specifying this option is equivalent to
|
||||||
spectre_v2=auto.
|
spectre_v2=auto.
|
||||||
|
@@ -212,6 +212,7 @@ enum spectre_v2_mitigation {
|
|||||||
SPECTRE_V2_EIBRS,
|
SPECTRE_V2_EIBRS,
|
||||||
SPECTRE_V2_EIBRS_RETPOLINE,
|
SPECTRE_V2_EIBRS_RETPOLINE,
|
||||||
SPECTRE_V2_EIBRS_LFENCE,
|
SPECTRE_V2_EIBRS_LFENCE,
|
||||||
|
SPECTRE_V2_IBRS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The indirect branch speculation control variants */
|
/* The indirect branch speculation control variants */
|
||||||
|
@@ -928,6 +928,7 @@ enum spectre_v2_mitigation_cmd {
|
|||||||
SPECTRE_V2_CMD_EIBRS,
|
SPECTRE_V2_CMD_EIBRS,
|
||||||
SPECTRE_V2_CMD_EIBRS_RETPOLINE,
|
SPECTRE_V2_CMD_EIBRS_RETPOLINE,
|
||||||
SPECTRE_V2_CMD_EIBRS_LFENCE,
|
SPECTRE_V2_CMD_EIBRS_LFENCE,
|
||||||
|
SPECTRE_V2_CMD_IBRS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum spectre_v2_user_cmd {
|
enum spectre_v2_user_cmd {
|
||||||
@@ -1000,11 +1001,12 @@ spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
|
|||||||
return SPECTRE_V2_USER_CMD_AUTO;
|
return SPECTRE_V2_USER_CMD_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
|
static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
|
||||||
{
|
{
|
||||||
return (mode == SPECTRE_V2_EIBRS ||
|
return mode == SPECTRE_V2_IBRS ||
|
||||||
mode == SPECTRE_V2_EIBRS_RETPOLINE ||
|
mode == SPECTRE_V2_EIBRS ||
|
||||||
mode == SPECTRE_V2_EIBRS_LFENCE);
|
mode == SPECTRE_V2_EIBRS_RETPOLINE ||
|
||||||
|
mode == SPECTRE_V2_EIBRS_LFENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
@@ -1069,12 +1071,12 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If no STIBP, enhanced IBRS is enabled or SMT impossible, STIBP is not
|
* If no STIBP, IBRS or enhanced IBRS is enabled, or SMT impossible,
|
||||||
* required.
|
* STIBP is not required.
|
||||||
*/
|
*/
|
||||||
if (!boot_cpu_has(X86_FEATURE_STIBP) ||
|
if (!boot_cpu_has(X86_FEATURE_STIBP) ||
|
||||||
!smt_possible ||
|
!smt_possible ||
|
||||||
spectre_v2_in_eibrs_mode(spectre_v2_enabled))
|
spectre_v2_in_ibrs_mode(spectre_v2_enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1106,6 +1108,7 @@ static const char * const spectre_v2_strings[] = {
|
|||||||
[SPECTRE_V2_EIBRS] = "Mitigation: Enhanced IBRS",
|
[SPECTRE_V2_EIBRS] = "Mitigation: Enhanced IBRS",
|
||||||
[SPECTRE_V2_EIBRS_LFENCE] = "Mitigation: Enhanced IBRS + LFENCE",
|
[SPECTRE_V2_EIBRS_LFENCE] = "Mitigation: Enhanced IBRS + LFENCE",
|
||||||
[SPECTRE_V2_EIBRS_RETPOLINE] = "Mitigation: Enhanced IBRS + Retpolines",
|
[SPECTRE_V2_EIBRS_RETPOLINE] = "Mitigation: Enhanced IBRS + Retpolines",
|
||||||
|
[SPECTRE_V2_IBRS] = "Mitigation: IBRS",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -1123,6 +1126,7 @@ static const struct {
|
|||||||
{ "eibrs,lfence", SPECTRE_V2_CMD_EIBRS_LFENCE, false },
|
{ "eibrs,lfence", SPECTRE_V2_CMD_EIBRS_LFENCE, false },
|
||||||
{ "eibrs,retpoline", SPECTRE_V2_CMD_EIBRS_RETPOLINE, false },
|
{ "eibrs,retpoline", SPECTRE_V2_CMD_EIBRS_RETPOLINE, false },
|
||||||
{ "auto", SPECTRE_V2_CMD_AUTO, false },
|
{ "auto", SPECTRE_V2_CMD_AUTO, false },
|
||||||
|
{ "ibrs", SPECTRE_V2_CMD_IBRS, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init spec_v2_print_cond(const char *reason, bool secure)
|
static void __init spec_v2_print_cond(const char *reason, bool secure)
|
||||||
@@ -1185,6 +1189,24 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
|
|||||||
return SPECTRE_V2_CMD_AUTO;
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
|
||||||
|
pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
|
||||||
|
mitigation_options[i].option);
|
||||||
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
|
||||||
|
pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
|
||||||
|
mitigation_options[i].option);
|
||||||
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
|
||||||
|
pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
|
||||||
|
mitigation_options[i].option);
|
||||||
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
spec_v2_print_cond(mitigation_options[i].option,
|
spec_v2_print_cond(mitigation_options[i].option,
|
||||||
mitigation_options[i].secure);
|
mitigation_options[i].secure);
|
||||||
return cmd;
|
return cmd;
|
||||||
@@ -1224,6 +1246,14 @@ static void __init spectre_v2_select_mitigation(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (boot_cpu_has_bug(X86_BUG_RETBLEED) &&
|
||||||
|
retbleed_cmd != RETBLEED_CMD_OFF &&
|
||||||
|
boot_cpu_has(X86_FEATURE_IBRS) &&
|
||||||
|
boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
|
||||||
|
mode = SPECTRE_V2_IBRS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
mode = spectre_v2_select_retpoline();
|
mode = spectre_v2_select_retpoline();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1240,6 +1270,10 @@ static void __init spectre_v2_select_mitigation(void)
|
|||||||
mode = spectre_v2_select_retpoline();
|
mode = spectre_v2_select_retpoline();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_CMD_IBRS:
|
||||||
|
mode = SPECTRE_V2_IBRS;
|
||||||
|
break;
|
||||||
|
|
||||||
case SPECTRE_V2_CMD_EIBRS:
|
case SPECTRE_V2_CMD_EIBRS:
|
||||||
mode = SPECTRE_V2_EIBRS;
|
mode = SPECTRE_V2_EIBRS;
|
||||||
break;
|
break;
|
||||||
@@ -1256,7 +1290,7 @@ static void __init spectre_v2_select_mitigation(void)
|
|||||||
if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
|
if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
|
||||||
pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
|
pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
|
||||||
|
|
||||||
if (spectre_v2_in_eibrs_mode(mode)) {
|
if (spectre_v2_in_ibrs_mode(mode)) {
|
||||||
/* Force it so VMEXIT will restore correctly */
|
/* Force it so VMEXIT will restore correctly */
|
||||||
x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
|
x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
|
||||||
write_spec_ctrl_current(x86_spec_ctrl_base, true);
|
write_spec_ctrl_current(x86_spec_ctrl_base, true);
|
||||||
@@ -1267,6 +1301,10 @@ static void __init spectre_v2_select_mitigation(void)
|
|||||||
case SPECTRE_V2_EIBRS:
|
case SPECTRE_V2_EIBRS:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_IBRS:
|
||||||
|
setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
|
||||||
|
break;
|
||||||
|
|
||||||
case SPECTRE_V2_LFENCE:
|
case SPECTRE_V2_LFENCE:
|
||||||
case SPECTRE_V2_EIBRS_LFENCE:
|
case SPECTRE_V2_EIBRS_LFENCE:
|
||||||
setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
|
setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
|
||||||
@@ -1293,17 +1331,17 @@ static void __init spectre_v2_select_mitigation(void)
|
|||||||
pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
|
pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retpoline means the kernel is safe because it has no indirect
|
* Retpoline protects the kernel, but doesn't protect firmware. IBRS
|
||||||
* branches. Enhanced IBRS protects firmware too, so, enable restricted
|
* and Enhanced IBRS protect firmware too, so enable IBRS around
|
||||||
* speculation around firmware calls only when Enhanced IBRS isn't
|
* firmware calls only when IBRS / Enhanced IBRS aren't otherwise
|
||||||
* supported.
|
* enabled.
|
||||||
*
|
*
|
||||||
* Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
|
* Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
|
||||||
* the user might select retpoline on the kernel command line and if
|
* the user might select retpoline on the kernel command line and if
|
||||||
* the CPU supports Enhanced IBRS, kernel might un-intentionally not
|
* the CPU supports Enhanced IBRS, kernel might un-intentionally not
|
||||||
* enable IBRS around firmware calls.
|
* enable IBRS around firmware calls.
|
||||||
*/
|
*/
|
||||||
if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_mode(mode)) {
|
if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
|
||||||
setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
|
setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
|
||||||
pr_info("Enabling Restricted Speculation for firmware calls\n");
|
pr_info("Enabling Restricted Speculation for firmware calls\n");
|
||||||
}
|
}
|
||||||
@@ -2012,7 +2050,7 @@ static ssize_t mmio_stale_data_show_state(char *buf)
|
|||||||
|
|
||||||
static char *stibp_state(void)
|
static char *stibp_state(void)
|
||||||
{
|
{
|
||||||
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
|
if (spectre_v2_in_ibrs_mode(spectre_v2_enabled))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
switch (spectre_v2_user_stibp) {
|
switch (spectre_v2_user_stibp) {
|
||||||
|
Reference in New Issue
Block a user