x86/speculation: Add eIBRS + Retpoline options
Thanks to the chaps at VUsec it is now clear that eIBRS is not sufficient, therefore allow enabling of retpolines along with eIBRS. Add spectre_v2=eibrs, spectre_v2=eibrs,lfence and spectre_v2=eibrs,retpoline options to explicitly pick your preferred means of mitigation. Since there's new mitigations there's also user visible changes in /sys/devices/system/cpu/vulnerabilities/spectre_v2 to reflect these new mitigations. [ bp: Massage commit message, trim error messages, do more precise eIBRS mode checking. ] Co-developed-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov <bp@suse.de> Reviewed-by: Patrick Colp <patrick.colp@oracle.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
d45476d983
commit
1e19da8522
|
@ -190,7 +190,9 @@ enum spectre_v2_mitigation {
|
||||||
SPECTRE_V2_NONE,
|
SPECTRE_V2_NONE,
|
||||||
SPECTRE_V2_RETPOLINE,
|
SPECTRE_V2_RETPOLINE,
|
||||||
SPECTRE_V2_LFENCE,
|
SPECTRE_V2_LFENCE,
|
||||||
SPECTRE_V2_IBRS_ENHANCED,
|
SPECTRE_V2_EIBRS,
|
||||||
|
SPECTRE_V2_EIBRS_RETPOLINE,
|
||||||
|
SPECTRE_V2_EIBRS_LFENCE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The indirect branch speculation control variants */
|
/* The indirect branch speculation control variants */
|
||||||
|
|
|
@ -665,6 +665,9 @@ enum spectre_v2_mitigation_cmd {
|
||||||
SPECTRE_V2_CMD_RETPOLINE,
|
SPECTRE_V2_CMD_RETPOLINE,
|
||||||
SPECTRE_V2_CMD_RETPOLINE_GENERIC,
|
SPECTRE_V2_CMD_RETPOLINE_GENERIC,
|
||||||
SPECTRE_V2_CMD_RETPOLINE_LFENCE,
|
SPECTRE_V2_CMD_RETPOLINE_LFENCE,
|
||||||
|
SPECTRE_V2_CMD_EIBRS,
|
||||||
|
SPECTRE_V2_CMD_EIBRS_RETPOLINE,
|
||||||
|
SPECTRE_V2_CMD_EIBRS_LFENCE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum spectre_v2_user_cmd {
|
enum spectre_v2_user_cmd {
|
||||||
|
@ -737,6 +740,13 @@ 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)
|
||||||
|
{
|
||||||
|
return (mode == SPECTRE_V2_EIBRS ||
|
||||||
|
mode == SPECTRE_V2_EIBRS_RETPOLINE ||
|
||||||
|
mode == SPECTRE_V2_EIBRS_LFENCE);
|
||||||
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
|
spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
|
||||||
{
|
{
|
||||||
|
@ -804,7 +814,7 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
|
||||||
*/
|
*/
|
||||||
if (!boot_cpu_has(X86_FEATURE_STIBP) ||
|
if (!boot_cpu_has(X86_FEATURE_STIBP) ||
|
||||||
!smt_possible ||
|
!smt_possible ||
|
||||||
spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
|
spectre_v2_in_eibrs_mode(spectre_v2_enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -826,7 +836,9 @@ static const char * const spectre_v2_strings[] = {
|
||||||
[SPECTRE_V2_NONE] = "Vulnerable",
|
[SPECTRE_V2_NONE] = "Vulnerable",
|
||||||
[SPECTRE_V2_RETPOLINE] = "Mitigation: Retpolines",
|
[SPECTRE_V2_RETPOLINE] = "Mitigation: Retpolines",
|
||||||
[SPECTRE_V2_LFENCE] = "Mitigation: LFENCE",
|
[SPECTRE_V2_LFENCE] = "Mitigation: LFENCE",
|
||||||
[SPECTRE_V2_IBRS_ENHANCED] = "Mitigation: Enhanced IBRS",
|
[SPECTRE_V2_EIBRS] = "Mitigation: Enhanced IBRS",
|
||||||
|
[SPECTRE_V2_EIBRS_LFENCE] = "Mitigation: Enhanced IBRS + LFENCE",
|
||||||
|
[SPECTRE_V2_EIBRS_RETPOLINE] = "Mitigation: Enhanced IBRS + Retpolines",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@ -840,6 +852,9 @@ static const struct {
|
||||||
{ "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_LFENCE, false },
|
{ "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_LFENCE, false },
|
||||||
{ "retpoline,lfence", SPECTRE_V2_CMD_RETPOLINE_LFENCE, false },
|
{ "retpoline,lfence", SPECTRE_V2_CMD_RETPOLINE_LFENCE, false },
|
||||||
{ "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
|
{ "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
|
||||||
|
{ "eibrs", SPECTRE_V2_CMD_EIBRS, false },
|
||||||
|
{ "eibrs,lfence", SPECTRE_V2_CMD_EIBRS_LFENCE, false },
|
||||||
|
{ "eibrs,retpoline", SPECTRE_V2_CMD_EIBRS_RETPOLINE, false },
|
||||||
{ "auto", SPECTRE_V2_CMD_AUTO, false },
|
{ "auto", SPECTRE_V2_CMD_AUTO, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -877,15 +892,29 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
|
||||||
|
|
||||||
if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
|
if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
|
||||||
cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
|
cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
|
||||||
cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
|
cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
|
||||||
|
cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
|
||||||
|
cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
|
||||||
!IS_ENABLED(CONFIG_RETPOLINE)) {
|
!IS_ENABLED(CONFIG_RETPOLINE)) {
|
||||||
pr_err("%s selected but not compiled in. Switching to AUTO select\n", mitigation_options[i].option);
|
pr_err("%s selected but not compiled in. Switching to AUTO select\n",
|
||||||
|
mitigation_options[i].option);
|
||||||
return SPECTRE_V2_CMD_AUTO;
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE) &&
|
if ((cmd == SPECTRE_V2_CMD_EIBRS ||
|
||||||
|
cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
|
||||||
|
cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
|
||||||
|
!boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
|
||||||
|
pr_err("%s selected but CPU doesn't have eIBRS. Switching to AUTO select\n",
|
||||||
|
mitigation_options[i].option);
|
||||||
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
|
||||||
|
cmd == SPECTRE_V2_CMD_EIBRS_LFENCE) &&
|
||||||
!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
|
!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
|
||||||
pr_err("%s selected, but CPU doesn't have a serializing LFENCE. Switching to AUTO select\n", mitigation_options[i].option);
|
pr_err("%s selected, but CPU doesn't have a serializing LFENCE. Switching to AUTO select\n",
|
||||||
|
mitigation_options[i].option);
|
||||||
return SPECTRE_V2_CMD_AUTO;
|
return SPECTRE_V2_CMD_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,6 +923,25 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
|
||||||
|
{
|
||||||
|
if (!IS_ENABLED(CONFIG_RETPOLINE)) {
|
||||||
|
pr_err("Kernel not compiled with retpoline; no mitigation available!");
|
||||||
|
return SPECTRE_V2_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
|
||||||
|
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
|
||||||
|
if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
|
||||||
|
pr_err("LFENCE not serializing, switching to generic retpoline\n");
|
||||||
|
return SPECTRE_V2_RETPOLINE;
|
||||||
|
}
|
||||||
|
return SPECTRE_V2_LFENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SPECTRE_V2_RETPOLINE;
|
||||||
|
}
|
||||||
|
|
||||||
static void __init spectre_v2_select_mitigation(void)
|
static void __init spectre_v2_select_mitigation(void)
|
||||||
{
|
{
|
||||||
enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
|
enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
|
||||||
|
@ -914,49 +962,60 @@ static void __init spectre_v2_select_mitigation(void)
|
||||||
case SPECTRE_V2_CMD_FORCE:
|
case SPECTRE_V2_CMD_FORCE:
|
||||||
case SPECTRE_V2_CMD_AUTO:
|
case SPECTRE_V2_CMD_AUTO:
|
||||||
if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
|
if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
|
||||||
mode = SPECTRE_V2_IBRS_ENHANCED;
|
mode = SPECTRE_V2_EIBRS;
|
||||||
/* Force it so VMEXIT will restore correctly */
|
break;
|
||||||
x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
|
|
||||||
wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
|
|
||||||
goto specv2_set_mode;
|
|
||||||
}
|
}
|
||||||
if (IS_ENABLED(CONFIG_RETPOLINE))
|
|
||||||
goto retpoline_auto;
|
mode = spectre_v2_select_retpoline();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPECTRE_V2_CMD_RETPOLINE_LFENCE:
|
case SPECTRE_V2_CMD_RETPOLINE_LFENCE:
|
||||||
if (IS_ENABLED(CONFIG_RETPOLINE))
|
|
||||||
goto retpoline_lfence;
|
|
||||||
break;
|
|
||||||
case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
|
|
||||||
if (IS_ENABLED(CONFIG_RETPOLINE))
|
|
||||||
goto retpoline_generic;
|
|
||||||
break;
|
|
||||||
case SPECTRE_V2_CMD_RETPOLINE:
|
|
||||||
if (IS_ENABLED(CONFIG_RETPOLINE))
|
|
||||||
goto retpoline_auto;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pr_err("Spectre mitigation: kernel not compiled with retpoline; no mitigation available!");
|
|
||||||
return;
|
|
||||||
|
|
||||||
retpoline_auto:
|
|
||||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
|
|
||||||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
|
|
||||||
retpoline_lfence:
|
|
||||||
if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
|
|
||||||
pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n");
|
|
||||||
goto retpoline_generic;
|
|
||||||
}
|
|
||||||
mode = SPECTRE_V2_LFENCE;
|
mode = SPECTRE_V2_LFENCE;
|
||||||
setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
|
break;
|
||||||
setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
|
|
||||||
} else {
|
case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
|
||||||
retpoline_generic:
|
|
||||||
mode = SPECTRE_V2_RETPOLINE;
|
mode = SPECTRE_V2_RETPOLINE;
|
||||||
setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_CMD_RETPOLINE:
|
||||||
|
mode = spectre_v2_select_retpoline();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_CMD_EIBRS:
|
||||||
|
mode = SPECTRE_V2_EIBRS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_CMD_EIBRS_LFENCE:
|
||||||
|
mode = SPECTRE_V2_EIBRS_LFENCE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_CMD_EIBRS_RETPOLINE:
|
||||||
|
mode = SPECTRE_V2_EIBRS_RETPOLINE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spectre_v2_in_eibrs_mode(mode)) {
|
||||||
|
/* Force it so VMEXIT will restore correctly */
|
||||||
|
x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
|
||||||
|
wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case SPECTRE_V2_NONE:
|
||||||
|
case SPECTRE_V2_EIBRS:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPECTRE_V2_LFENCE:
|
||||||
|
case SPECTRE_V2_EIBRS_LFENCE:
|
||||||
|
setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
|
||||||
|
fallthrough;
|
||||||
|
|
||||||
|
case SPECTRE_V2_RETPOLINE:
|
||||||
|
case SPECTRE_V2_EIBRS_RETPOLINE:
|
||||||
|
setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
specv2_set_mode:
|
|
||||||
spectre_v2_enabled = mode;
|
spectre_v2_enabled = mode;
|
||||||
pr_info("%s\n", spectre_v2_strings[mode]);
|
pr_info("%s\n", spectre_v2_strings[mode]);
|
||||||
|
|
||||||
|
@ -982,7 +1041,7 @@ specv2_set_mode:
|
||||||
* 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) && mode != SPECTRE_V2_IBRS_ENHANCED) {
|
if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_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");
|
||||||
}
|
}
|
||||||
|
@ -1691,7 +1750,7 @@ static ssize_t tsx_async_abort_show_state(char *buf)
|
||||||
|
|
||||||
static char *stibp_state(void)
|
static char *stibp_state(void)
|
||||||
{
|
{
|
||||||
if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
|
if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
switch (spectre_v2_user_stibp) {
|
switch (spectre_v2_user_stibp) {
|
||||||
|
|
Loading…
Reference in New Issue