mirror of https://github.com/torvalds/linux.git
x86/bugs: Restructure retbleed mitigation
Restructure retbleed mitigation to use select/update/apply functions to create consistent vulnerability handling. The retbleed_update_mitigation() simplifies the dependency between spectre_v2 and retbleed. The command line options now directly select a preferred mitigation which simplifies the logic. Signed-off-by: David Kaplan <david.kaplan@amd.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Reviewed-by: Josh Poimboeuf <jpoimboe@kernel.org> Link: https://lore.kernel.org/20250418161721.1855190-11-david.kaplan@amd.com
This commit is contained in:
parent
83d4b19331
commit
e3b78a7ad5
|
|
@ -57,6 +57,8 @@ static void __init spectre_v1_select_mitigation(void);
|
|||
static void __init spectre_v1_apply_mitigation(void);
|
||||
static void __init spectre_v2_select_mitigation(void);
|
||||
static void __init retbleed_select_mitigation(void);
|
||||
static void __init retbleed_update_mitigation(void);
|
||||
static void __init retbleed_apply_mitigation(void);
|
||||
static void __init spectre_v2_user_select_mitigation(void);
|
||||
static void __init ssb_select_mitigation(void);
|
||||
static void __init l1tf_select_mitigation(void);
|
||||
|
|
@ -187,11 +189,6 @@ void __init cpu_select_mitigations(void)
|
|||
/* Select the proper CPU mitigations before patching alternatives: */
|
||||
spectre_v1_select_mitigation();
|
||||
spectre_v2_select_mitigation();
|
||||
/*
|
||||
* retbleed_select_mitigation() relies on the state set by
|
||||
* spectre_v2_select_mitigation(); specifically it wants to know about
|
||||
* spectre_v2=ibrs.
|
||||
*/
|
||||
retbleed_select_mitigation();
|
||||
/*
|
||||
* spectre_v2_user_select_mitigation() relies on the state set by
|
||||
|
|
@ -219,12 +216,14 @@ void __init cpu_select_mitigations(void)
|
|||
* After mitigations are selected, some may need to update their
|
||||
* choices.
|
||||
*/
|
||||
retbleed_update_mitigation();
|
||||
mds_update_mitigation();
|
||||
taa_update_mitigation();
|
||||
mmio_update_mitigation();
|
||||
rfds_update_mitigation();
|
||||
|
||||
spectre_v1_apply_mitigation();
|
||||
retbleed_apply_mitigation();
|
||||
mds_apply_mitigation();
|
||||
taa_apply_mitigation();
|
||||
mmio_apply_mitigation();
|
||||
|
|
@ -1085,6 +1084,7 @@ enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = SPECTRE_V2_NONE;
|
|||
|
||||
enum retbleed_mitigation {
|
||||
RETBLEED_MITIGATION_NONE,
|
||||
RETBLEED_MITIGATION_AUTO,
|
||||
RETBLEED_MITIGATION_UNRET,
|
||||
RETBLEED_MITIGATION_IBPB,
|
||||
RETBLEED_MITIGATION_IBRS,
|
||||
|
|
@ -1092,14 +1092,6 @@ enum retbleed_mitigation {
|
|||
RETBLEED_MITIGATION_STUFF,
|
||||
};
|
||||
|
||||
enum retbleed_mitigation_cmd {
|
||||
RETBLEED_CMD_OFF,
|
||||
RETBLEED_CMD_AUTO,
|
||||
RETBLEED_CMD_UNRET,
|
||||
RETBLEED_CMD_IBPB,
|
||||
RETBLEED_CMD_STUFF,
|
||||
};
|
||||
|
||||
static const char * const retbleed_strings[] = {
|
||||
[RETBLEED_MITIGATION_NONE] = "Vulnerable",
|
||||
[RETBLEED_MITIGATION_UNRET] = "Mitigation: untrained return thunk",
|
||||
|
|
@ -1110,9 +1102,7 @@ static const char * const retbleed_strings[] = {
|
|||
};
|
||||
|
||||
static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
|
||||
RETBLEED_MITIGATION_NONE;
|
||||
static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
|
||||
IS_ENABLED(CONFIG_MITIGATION_RETBLEED) ? RETBLEED_CMD_AUTO : RETBLEED_CMD_OFF;
|
||||
IS_ENABLED(CONFIG_MITIGATION_RETBLEED) ? RETBLEED_MITIGATION_AUTO : RETBLEED_MITIGATION_NONE;
|
||||
|
||||
static int __ro_after_init retbleed_nosmt = false;
|
||||
|
||||
|
|
@ -1129,15 +1119,15 @@ static int __init retbleed_parse_cmdline(char *str)
|
|||
}
|
||||
|
||||
if (!strcmp(str, "off")) {
|
||||
retbleed_cmd = RETBLEED_CMD_OFF;
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_NONE;
|
||||
} else if (!strcmp(str, "auto")) {
|
||||
retbleed_cmd = RETBLEED_CMD_AUTO;
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
} else if (!strcmp(str, "unret")) {
|
||||
retbleed_cmd = RETBLEED_CMD_UNRET;
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
|
||||
} else if (!strcmp(str, "ibpb")) {
|
||||
retbleed_cmd = RETBLEED_CMD_IBPB;
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
|
||||
} else if (!strcmp(str, "stuff")) {
|
||||
retbleed_cmd = RETBLEED_CMD_STUFF;
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_STUFF;
|
||||
} else if (!strcmp(str, "nosmt")) {
|
||||
retbleed_nosmt = true;
|
||||
} else if (!strcmp(str, "force")) {
|
||||
|
|
@ -1158,76 +1148,109 @@ early_param("retbleed", retbleed_parse_cmdline);
|
|||
|
||||
static void __init retbleed_select_mitigation(void)
|
||||
{
|
||||
bool mitigate_smt = false;
|
||||
|
||||
if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
|
||||
if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off()) {
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_NONE;
|
||||
return;
|
||||
|
||||
switch (retbleed_cmd) {
|
||||
case RETBLEED_CMD_OFF:
|
||||
return;
|
||||
|
||||
case RETBLEED_CMD_UNRET:
|
||||
if (IS_ENABLED(CONFIG_MITIGATION_UNRET_ENTRY)) {
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
|
||||
} else {
|
||||
pr_err("WARNING: kernel not compiled with MITIGATION_UNRET_ENTRY.\n");
|
||||
goto do_cmd_auto;
|
||||
}
|
||||
break;
|
||||
|
||||
case RETBLEED_CMD_IBPB:
|
||||
if (!boot_cpu_has(X86_FEATURE_IBPB)) {
|
||||
pr_err("WARNING: CPU does not support IBPB.\n");
|
||||
goto do_cmd_auto;
|
||||
} else if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY)) {
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
|
||||
} else {
|
||||
pr_err("WARNING: kernel not compiled with MITIGATION_IBPB_ENTRY.\n");
|
||||
goto do_cmd_auto;
|
||||
}
|
||||
break;
|
||||
|
||||
case RETBLEED_CMD_STUFF:
|
||||
if (IS_ENABLED(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) &&
|
||||
spectre_v2_enabled == SPECTRE_V2_RETPOLINE) {
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
|
||||
pr_err("WARNING: retbleed=stuff only supported for Intel CPUs.\n");
|
||||
goto do_cmd_auto;
|
||||
}
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_STUFF;
|
||||
|
||||
} else {
|
||||
if (IS_ENABLED(CONFIG_MITIGATION_CALL_DEPTH_TRACKING))
|
||||
pr_err("WARNING: retbleed=stuff depends on spectre_v2=retpoline\n");
|
||||
else
|
||||
pr_err("WARNING: kernel not compiled with MITIGATION_CALL_DEPTH_TRACKING.\n");
|
||||
|
||||
goto do_cmd_auto;
|
||||
}
|
||||
break;
|
||||
|
||||
do_cmd_auto:
|
||||
case RETBLEED_CMD_AUTO:
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
|
||||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
|
||||
if (IS_ENABLED(CONFIG_MITIGATION_UNRET_ENTRY))
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
|
||||
else if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY) &&
|
||||
boot_cpu_has(X86_FEATURE_IBPB))
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Intel mitigation (IBRS or eIBRS) was already selected in
|
||||
* spectre_v2_select_mitigation(). 'retbleed_mitigation' will
|
||||
* be set accordingly below.
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
switch (retbleed_mitigation) {
|
||||
case RETBLEED_MITIGATION_UNRET:
|
||||
if (!IS_ENABLED(CONFIG_MITIGATION_UNRET_ENTRY)) {
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
pr_err("WARNING: kernel not compiled with MITIGATION_UNRET_ENTRY.\n");
|
||||
}
|
||||
break;
|
||||
case RETBLEED_MITIGATION_IBPB:
|
||||
if (!boot_cpu_has(X86_FEATURE_IBPB)) {
|
||||
pr_err("WARNING: CPU does not support IBPB.\n");
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
} else if (!IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY)) {
|
||||
pr_err("WARNING: kernel not compiled with MITIGATION_IBPB_ENTRY.\n");
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
}
|
||||
break;
|
||||
case RETBLEED_MITIGATION_STUFF:
|
||||
if (!IS_ENABLED(CONFIG_MITIGATION_CALL_DEPTH_TRACKING)) {
|
||||
pr_err("WARNING: kernel not compiled with MITIGATION_CALL_DEPTH_TRACKING.\n");
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
} else if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
|
||||
pr_err("WARNING: retbleed=stuff only supported for Intel CPUs.\n");
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (retbleed_mitigation != RETBLEED_MITIGATION_AUTO)
|
||||
return;
|
||||
|
||||
/* Intel mitigation selected in retbleed_update_mitigation() */
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
|
||||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
|
||||
if (IS_ENABLED(CONFIG_MITIGATION_UNRET_ENTRY))
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
|
||||
else if (IS_ENABLED(CONFIG_MITIGATION_IBPB_ENTRY) &&
|
||||
boot_cpu_has(X86_FEATURE_IBPB))
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
|
||||
else
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init retbleed_update_mitigation(void)
|
||||
{
|
||||
if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
|
||||
return;
|
||||
|
||||
if (retbleed_mitigation == RETBLEED_MITIGATION_NONE)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* retbleed=stuff is only allowed on Intel. If stuffing can't be used
|
||||
* then a different mitigation will be selected below.
|
||||
*/
|
||||
if (retbleed_mitigation == RETBLEED_MITIGATION_STUFF) {
|
||||
if (spectre_v2_enabled != SPECTRE_V2_RETPOLINE) {
|
||||
pr_err("WARNING: retbleed=stuff depends on spectre_v2=retpoline\n");
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_AUTO;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Let IBRS trump all on Intel without affecting the effects of the
|
||||
* retbleed= cmdline option except for call depth based stuffing
|
||||
*/
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
|
||||
switch (spectre_v2_enabled) {
|
||||
case SPECTRE_V2_IBRS:
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
|
||||
break;
|
||||
case SPECTRE_V2_EIBRS:
|
||||
case SPECTRE_V2_EIBRS_RETPOLINE:
|
||||
case SPECTRE_V2_EIBRS_LFENCE:
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
|
||||
break;
|
||||
default:
|
||||
if (retbleed_mitigation != RETBLEED_MITIGATION_STUFF)
|
||||
pr_err(RETBLEED_INTEL_MSG);
|
||||
}
|
||||
/* If nothing has set the mitigation yet, default to NONE. */
|
||||
if (retbleed_mitigation == RETBLEED_MITIGATION_AUTO)
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_NONE;
|
||||
}
|
||||
out:
|
||||
pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
|
||||
}
|
||||
|
||||
|
||||
static void __init retbleed_apply_mitigation(void)
|
||||
{
|
||||
bool mitigate_smt = false;
|
||||
|
||||
switch (retbleed_mitigation) {
|
||||
case RETBLEED_MITIGATION_NONE:
|
||||
return;
|
||||
|
||||
case RETBLEED_MITIGATION_UNRET:
|
||||
setup_force_cpu_cap(X86_FEATURE_RETHUNK);
|
||||
setup_force_cpu_cap(X86_FEATURE_UNRET);
|
||||
|
|
@ -1277,28 +1300,6 @@ static void __init retbleed_select_mitigation(void)
|
|||
if (mitigate_smt && !boot_cpu_has(X86_FEATURE_STIBP) &&
|
||||
(retbleed_nosmt || cpu_mitigations_auto_nosmt()))
|
||||
cpu_smt_disable(false);
|
||||
|
||||
/*
|
||||
* Let IBRS trump all on Intel without affecting the effects of the
|
||||
* retbleed= cmdline option except for call depth based stuffing
|
||||
*/
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
|
||||
switch (spectre_v2_enabled) {
|
||||
case SPECTRE_V2_IBRS:
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
|
||||
break;
|
||||
case SPECTRE_V2_EIBRS:
|
||||
case SPECTRE_V2_EIBRS_RETPOLINE:
|
||||
case SPECTRE_V2_EIBRS_LFENCE:
|
||||
retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
|
||||
break;
|
||||
default:
|
||||
if (retbleed_mitigation != RETBLEED_MITIGATION_STUFF)
|
||||
pr_err(RETBLEED_INTEL_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
|
||||
}
|
||||
|
||||
#undef pr_fmt
|
||||
|
|
@ -1855,8 +1856,8 @@ static void __init spectre_v2_select_mitigation(void)
|
|||
|
||||
if (IS_ENABLED(CONFIG_MITIGATION_IBRS_ENTRY) &&
|
||||
boot_cpu_has_bug(X86_BUG_RETBLEED) &&
|
||||
retbleed_cmd != RETBLEED_CMD_OFF &&
|
||||
retbleed_cmd != RETBLEED_CMD_STUFF &&
|
||||
retbleed_mitigation != RETBLEED_MITIGATION_NONE &&
|
||||
retbleed_mitigation != RETBLEED_MITIGATION_STUFF &&
|
||||
boot_cpu_has(X86_FEATURE_IBRS) &&
|
||||
boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
|
||||
mode = SPECTRE_V2_IBRS;
|
||||
|
|
@ -1964,7 +1965,7 @@ static void __init spectre_v2_select_mitigation(void)
|
|||
(boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
|
||||
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) {
|
||||
|
||||
if (retbleed_cmd != RETBLEED_CMD_IBPB) {
|
||||
if (retbleed_mitigation != RETBLEED_MITIGATION_IBPB) {
|
||||
setup_force_cpu_cap(X86_FEATURE_USE_IBPB_FW);
|
||||
pr_info("Enabling Speculation Barrier for firmware calls\n");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue