|
|
|
|
@@ -434,6 +434,9 @@ static bool __init should_mitigate_vuln(unsigned int bug)
|
|
|
|
|
case X86_BUG_SPEC_STORE_BYPASS:
|
|
|
|
|
return cpu_attack_vector_mitigated(CPU_MITIGATE_USER_USER);
|
|
|
|
|
|
|
|
|
|
case X86_BUG_VMSCAPE:
|
|
|
|
|
return cpu_attack_vector_mitigated(CPU_MITIGATE_GUEST_HOST);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
WARN(1, "Unknown bug %x\n", bug);
|
|
|
|
|
return false;
|
|
|
|
|
@@ -684,8 +687,7 @@ static const char * const mmio_strings[] = {
|
|
|
|
|
|
|
|
|
|
static void __init mmio_select_mitigation(void)
|
|
|
|
|
{
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
|
|
|
|
|
cpu_mitigations_off()) {
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) {
|
|
|
|
|
mmio_mitigation = MMIO_MITIGATION_OFF;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -1460,8 +1462,10 @@ static void __init retbleed_update_mitigation(void)
|
|
|
|
|
retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (retbleed_mitigation != RETBLEED_MITIGATION_STUFF)
|
|
|
|
|
if (retbleed_mitigation != RETBLEED_MITIGATION_STUFF) {
|
|
|
|
|
pr_err(RETBLEED_INTEL_MSG);
|
|
|
|
|
retbleed_mitigation = RETBLEED_MITIGATION_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1842,9 +1846,10 @@ enum spectre_v2_mitigation_cmd {
|
|
|
|
|
SPECTRE_V2_CMD_IBRS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static enum spectre_v2_mitigation_cmd spectre_v2_cmd __ro_after_init = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
static enum spectre_v2_mitigation_cmd spectre_v2_cmd __ro_after_init =
|
|
|
|
|
IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2) ? SPECTRE_V2_CMD_AUTO : SPECTRE_V2_CMD_NONE;
|
|
|
|
|
|
|
|
|
|
enum spectre_v2_user_cmd {
|
|
|
|
|
enum spectre_v2_user_mitigation_cmd {
|
|
|
|
|
SPECTRE_V2_USER_CMD_NONE,
|
|
|
|
|
SPECTRE_V2_USER_CMD_AUTO,
|
|
|
|
|
SPECTRE_V2_USER_CMD_FORCE,
|
|
|
|
|
@@ -1854,6 +1859,9 @@ enum spectre_v2_user_cmd {
|
|
|
|
|
SPECTRE_V2_USER_CMD_SECCOMP_IBPB,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static enum spectre_v2_user_mitigation_cmd spectre_v2_user_cmd __ro_after_init =
|
|
|
|
|
IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2) ? SPECTRE_V2_USER_CMD_AUTO : SPECTRE_V2_USER_CMD_NONE;
|
|
|
|
|
|
|
|
|
|
static const char * const spectre_v2_user_strings[] = {
|
|
|
|
|
[SPECTRE_V2_USER_NONE] = "User space: Vulnerable",
|
|
|
|
|
[SPECTRE_V2_USER_STRICT] = "User space: Mitigation: STIBP protection",
|
|
|
|
|
@@ -1862,50 +1870,31 @@ static const char * const spectre_v2_user_strings[] = {
|
|
|
|
|
[SPECTRE_V2_USER_SECCOMP] = "User space: Mitigation: STIBP via seccomp and prctl",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char *option;
|
|
|
|
|
enum spectre_v2_user_cmd cmd;
|
|
|
|
|
bool secure;
|
|
|
|
|
} v2_user_options[] __initconst = {
|
|
|
|
|
{ "auto", SPECTRE_V2_USER_CMD_AUTO, false },
|
|
|
|
|
{ "off", SPECTRE_V2_USER_CMD_NONE, false },
|
|
|
|
|
{ "on", SPECTRE_V2_USER_CMD_FORCE, true },
|
|
|
|
|
{ "prctl", SPECTRE_V2_USER_CMD_PRCTL, false },
|
|
|
|
|
{ "prctl,ibpb", SPECTRE_V2_USER_CMD_PRCTL_IBPB, false },
|
|
|
|
|
{ "seccomp", SPECTRE_V2_USER_CMD_SECCOMP, false },
|
|
|
|
|
{ "seccomp,ibpb", SPECTRE_V2_USER_CMD_SECCOMP_IBPB, false },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void __init spec_v2_user_print_cond(const char *reason, bool secure)
|
|
|
|
|
static int __init spectre_v2_user_parse_cmdline(char *str)
|
|
|
|
|
{
|
|
|
|
|
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(void)
|
|
|
|
|
{
|
|
|
|
|
char arg[20];
|
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2))
|
|
|
|
|
return SPECTRE_V2_USER_CMD_NONE;
|
|
|
|
|
|
|
|
|
|
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 default\n", arg);
|
|
|
|
|
return SPECTRE_V2_USER_CMD_AUTO;
|
|
|
|
|
if (!str)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(str, "auto"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_AUTO;
|
|
|
|
|
else if (!strcmp(str, "off"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_NONE;
|
|
|
|
|
else if (!strcmp(str, "on"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_FORCE;
|
|
|
|
|
else if (!strcmp(str, "prctl"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_PRCTL;
|
|
|
|
|
else if (!strcmp(str, "prctl,ibpb"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_PRCTL_IBPB;
|
|
|
|
|
else if (!strcmp(str, "seccomp"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_SECCOMP;
|
|
|
|
|
else if (!strcmp(str, "seccomp,ibpb"))
|
|
|
|
|
spectre_v2_user_cmd = SPECTRE_V2_USER_CMD_SECCOMP_IBPB;
|
|
|
|
|
else
|
|
|
|
|
pr_err("Ignoring unknown spectre_v2_user option (%s).", str);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
early_param("spectre_v2_user", spectre_v2_user_parse_cmdline);
|
|
|
|
|
|
|
|
|
|
static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
|
|
|
|
|
{
|
|
|
|
|
@@ -1917,7 +1906,7 @@ static void __init spectre_v2_user_select_mitigation(void)
|
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_IBPB) && !boot_cpu_has(X86_FEATURE_STIBP))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (spectre_v2_parse_user_cmdline()) {
|
|
|
|
|
switch (spectre_v2_user_cmd) {
|
|
|
|
|
case SPECTRE_V2_USER_CMD_NONE:
|
|
|
|
|
return;
|
|
|
|
|
case SPECTRE_V2_USER_CMD_FORCE:
|
|
|
|
|
@@ -2045,119 +2034,61 @@ static void __init spectre_v2_user_apply_mitigation(void)
|
|
|
|
|
static const char * const spectre_v2_strings[] = {
|
|
|
|
|
[SPECTRE_V2_NONE] = "Vulnerable",
|
|
|
|
|
[SPECTRE_V2_RETPOLINE] = "Mitigation: Retpolines",
|
|
|
|
|
[SPECTRE_V2_LFENCE] = "Mitigation: LFENCE",
|
|
|
|
|
[SPECTRE_V2_LFENCE] = "Vulnerable: LFENCE",
|
|
|
|
|
[SPECTRE_V2_EIBRS] = "Mitigation: Enhanced / Automatic IBRS",
|
|
|
|
|
[SPECTRE_V2_EIBRS_LFENCE] = "Mitigation: Enhanced / Automatic IBRS + LFENCE",
|
|
|
|
|
[SPECTRE_V2_EIBRS_RETPOLINE] = "Mitigation: Enhanced / Automatic IBRS + Retpolines",
|
|
|
|
|
[SPECTRE_V2_IBRS] = "Mitigation: IBRS",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char *option;
|
|
|
|
|
enum spectre_v2_mitigation_cmd cmd;
|
|
|
|
|
bool secure;
|
|
|
|
|
} mitigation_options[] __initconst = {
|
|
|
|
|
{ "off", SPECTRE_V2_CMD_NONE, false },
|
|
|
|
|
{ "on", SPECTRE_V2_CMD_FORCE, true },
|
|
|
|
|
{ "retpoline", SPECTRE_V2_CMD_RETPOLINE, false },
|
|
|
|
|
{ "retpoline,amd", SPECTRE_V2_CMD_RETPOLINE_LFENCE, false },
|
|
|
|
|
{ "retpoline,lfence", SPECTRE_V2_CMD_RETPOLINE_LFENCE, 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 },
|
|
|
|
|
{ "ibrs", SPECTRE_V2_CMD_IBRS, false },
|
|
|
|
|
};
|
|
|
|
|
static bool nospectre_v2 __ro_after_init;
|
|
|
|
|
|
|
|
|
|
static void __init spec_v2_print_cond(const char *reason, bool secure)
|
|
|
|
|
static int __init nospectre_v2_parse_cmdline(char *str)
|
|
|
|
|
{
|
|
|
|
|
if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2) != secure)
|
|
|
|
|
pr_info("%s selected on command line.\n", reason);
|
|
|
|
|
nospectre_v2 = true;
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_NONE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
early_param("nospectre_v2", nospectre_v2_parse_cmdline);
|
|
|
|
|
|
|
|
|
|
static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
|
|
|
|
|
static int __init spectre_v2_parse_cmdline(char *str)
|
|
|
|
|
{
|
|
|
|
|
enum spectre_v2_mitigation_cmd cmd;
|
|
|
|
|
char arg[20];
|
|
|
|
|
int ret, i;
|
|
|
|
|
if (!str)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
cmd = IS_ENABLED(CONFIG_MITIGATION_SPECTRE_V2) ? SPECTRE_V2_CMD_AUTO : SPECTRE_V2_CMD_NONE;
|
|
|
|
|
if (cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
|
|
|
|
|
return SPECTRE_V2_CMD_NONE;
|
|
|
|
|
if (nospectre_v2)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, sizeof(arg));
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return cmd;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
|
|
|
|
|
if (!match_option(arg, ret, mitigation_options[i].option))
|
|
|
|
|
continue;
|
|
|
|
|
cmd = mitigation_options[i].cmd;
|
|
|
|
|
break;
|
|
|
|
|
if (!strcmp(str, "off")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_NONE;
|
|
|
|
|
} else if (!strcmp(str, "on")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_FORCE;
|
|
|
|
|
setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
|
|
|
|
|
setup_force_cpu_bug(X86_BUG_SPECTRE_V2_USER);
|
|
|
|
|
} else if (!strcmp(str, "retpoline")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_RETPOLINE;
|
|
|
|
|
} else if (!strcmp(str, "retpoline,amd") ||
|
|
|
|
|
!strcmp(str, "retpoline,lfence")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_RETPOLINE_LFENCE;
|
|
|
|
|
} else if (!strcmp(str, "retpoline,generic")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_RETPOLINE_GENERIC;
|
|
|
|
|
} else if (!strcmp(str, "eibrs")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_EIBRS;
|
|
|
|
|
} else if (!strcmp(str, "eibrs,lfence")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_EIBRS_LFENCE;
|
|
|
|
|
} else if (!strcmp(str, "eibrs,retpoline")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_EIBRS_RETPOLINE;
|
|
|
|
|
} else if (!strcmp(str, "auto")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
} else if (!strcmp(str, "ibrs")) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_IBRS;
|
|
|
|
|
} else {
|
|
|
|
|
pr_err("Ignoring unknown spectre_v2 option (%s).", str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i >= ARRAY_SIZE(mitigation_options)) {
|
|
|
|
|
pr_err("unknown option (%s). Switching to default mode\n", arg);
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
|
|
|
|
|
cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
|
|
|
|
|
cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
|
|
|
|
|
cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
|
|
|
|
|
cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
|
|
|
|
|
!IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)) {
|
|
|
|
|
pr_err("%s selected but not compiled in. Switching to AUTO select\n",
|
|
|
|
|
mitigation_options[i].option);
|
|
|
|
|
return SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 Enhanced or Automatic IBRS. 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)) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cmd == SPECTRE_V2_CMD_IBRS && !IS_ENABLED(CONFIG_MITIGATION_IBRS_ENTRY)) {
|
|
|
|
|
pr_err("%s selected but not compiled in. Switching to AUTO select\n",
|
|
|
|
|
mitigation_options[i].option);
|
|
|
|
|
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 && cpu_feature_enabled(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,
|
|
|
|
|
mitigation_options[i].secure);
|
|
|
|
|
return cmd;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
early_param("spectre_v2", spectre_v2_parse_cmdline);
|
|
|
|
|
|
|
|
|
|
static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
|
|
|
|
|
{
|
|
|
|
|
@@ -2306,10 +2237,6 @@ static void __init bhi_update_mitigation(void)
|
|
|
|
|
{
|
|
|
|
|
if (spectre_v2_cmd == SPECTRE_V2_CMD_NONE)
|
|
|
|
|
bhi_mitigation = BHI_MITIGATION_OFF;
|
|
|
|
|
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) &&
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_AUTO)
|
|
|
|
|
bhi_mitigation = BHI_MITIGATION_OFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init bhi_apply_mitigation(void)
|
|
|
|
|
@@ -2345,11 +2272,55 @@ static void __init bhi_apply_mitigation(void)
|
|
|
|
|
|
|
|
|
|
static void __init spectre_v2_select_mitigation(void)
|
|
|
|
|
{
|
|
|
|
|
spectre_v2_cmd = spectre_v2_parse_cmdline();
|
|
|
|
|
if ((spectre_v2_cmd == SPECTRE_V2_CMD_RETPOLINE ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
|
|
|
|
|
!IS_ENABLED(CONFIG_MITIGATION_RETPOLINE)) {
|
|
|
|
|
pr_err("RETPOLINE selected but not compiled in. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) &&
|
|
|
|
|
(spectre_v2_cmd == SPECTRE_V2_CMD_NONE || spectre_v2_cmd == SPECTRE_V2_CMD_AUTO))
|
|
|
|
|
if ((spectre_v2_cmd == SPECTRE_V2_CMD_EIBRS ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
|
|
|
|
|
!boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
|
|
|
|
|
pr_err("EIBRS selected but CPU doesn't have Enhanced or Automatic IBRS. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((spectre_v2_cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
|
|
|
|
|
spectre_v2_cmd == SPECTRE_V2_CMD_EIBRS_LFENCE) &&
|
|
|
|
|
!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
|
|
|
|
|
pr_err("LFENCE selected, but CPU doesn't have a serializing LFENCE. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (spectre_v2_cmd == SPECTRE_V2_CMD_IBRS && !IS_ENABLED(CONFIG_MITIGATION_IBRS_ENTRY)) {
|
|
|
|
|
pr_err("IBRS selected but not compiled in. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (spectre_v2_cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
|
|
|
|
|
pr_err("IBRS selected but not Intel CPU. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (spectre_v2_cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
|
|
|
|
|
pr_err("IBRS selected but CPU doesn't have IBRS. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (spectre_v2_cmd == SPECTRE_V2_CMD_IBRS && cpu_feature_enabled(X86_FEATURE_XENPV)) {
|
|
|
|
|
pr_err("IBRS selected but running as XenPV guest. Switching to AUTO select\n");
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_AUTO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) {
|
|
|
|
|
spectre_v2_cmd = SPECTRE_V2_CMD_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (spectre_v2_cmd) {
|
|
|
|
|
case SPECTRE_V2_CMD_NONE:
|
|
|
|
|
@@ -2555,16 +2526,8 @@ static void update_mds_branch_idle(void)
|
|
|
|
|
#undef pr_fmt
|
|
|
|
|
#define pr_fmt(fmt) "Speculative Store Bypass: " fmt
|
|
|
|
|
|
|
|
|
|
static enum ssb_mitigation ssb_mode __ro_after_init = SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
|
|
|
|
|
/* The kernel command line selection */
|
|
|
|
|
enum ssb_mitigation_cmd {
|
|
|
|
|
SPEC_STORE_BYPASS_CMD_NONE,
|
|
|
|
|
SPEC_STORE_BYPASS_CMD_AUTO,
|
|
|
|
|
SPEC_STORE_BYPASS_CMD_ON,
|
|
|
|
|
SPEC_STORE_BYPASS_CMD_PRCTL,
|
|
|
|
|
SPEC_STORE_BYPASS_CMD_SECCOMP,
|
|
|
|
|
};
|
|
|
|
|
static enum ssb_mitigation ssb_mode __ro_after_init =
|
|
|
|
|
IS_ENABLED(CONFIG_MITIGATION_SSB) ? SPEC_STORE_BYPASS_AUTO : SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
|
|
|
|
|
static const char * const ssb_strings[] = {
|
|
|
|
|
[SPEC_STORE_BYPASS_NONE] = "Vulnerable",
|
|
|
|
|
@@ -2573,94 +2536,61 @@ static const char * const ssb_strings[] = {
|
|
|
|
|
[SPEC_STORE_BYPASS_SECCOMP] = "Mitigation: Speculative Store Bypass disabled via prctl and seccomp",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
const char *option;
|
|
|
|
|
enum ssb_mitigation_cmd cmd;
|
|
|
|
|
} ssb_mitigation_options[] __initconst = {
|
|
|
|
|
{ "auto", SPEC_STORE_BYPASS_CMD_AUTO }, /* Platform decides */
|
|
|
|
|
{ "on", SPEC_STORE_BYPASS_CMD_ON }, /* Disable Speculative Store Bypass */
|
|
|
|
|
{ "off", SPEC_STORE_BYPASS_CMD_NONE }, /* Don't touch Speculative Store Bypass */
|
|
|
|
|
{ "prctl", SPEC_STORE_BYPASS_CMD_PRCTL }, /* Disable Speculative Store Bypass via prctl */
|
|
|
|
|
{ "seccomp", SPEC_STORE_BYPASS_CMD_SECCOMP }, /* Disable Speculative Store Bypass via prctl and seccomp */
|
|
|
|
|
};
|
|
|
|
|
static bool nossb __ro_after_init;
|
|
|
|
|
|
|
|
|
|
static enum ssb_mitigation_cmd __init ssb_parse_cmdline(void)
|
|
|
|
|
static int __init nossb_parse_cmdline(char *str)
|
|
|
|
|
{
|
|
|
|
|
enum ssb_mitigation_cmd cmd;
|
|
|
|
|
char arg[20];
|
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
|
|
cmd = IS_ENABLED(CONFIG_MITIGATION_SSB) ?
|
|
|
|
|
SPEC_STORE_BYPASS_CMD_AUTO : SPEC_STORE_BYPASS_CMD_NONE;
|
|
|
|
|
if (cmdline_find_option_bool(boot_command_line, "nospec_store_bypass_disable") ||
|
|
|
|
|
cpu_mitigations_off()) {
|
|
|
|
|
return SPEC_STORE_BYPASS_CMD_NONE;
|
|
|
|
|
} else {
|
|
|
|
|
ret = cmdline_find_option(boot_command_line, "spec_store_bypass_disable",
|
|
|
|
|
arg, sizeof(arg));
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return cmd;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ssb_mitigation_options); i++) {
|
|
|
|
|
if (!match_option(arg, ret, ssb_mitigation_options[i].option))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
cmd = ssb_mitigation_options[i].cmd;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i >= ARRAY_SIZE(ssb_mitigation_options)) {
|
|
|
|
|
pr_err("unknown option (%s). Switching to default mode\n", arg);
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
|
nossb = true;
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
early_param("nospec_store_bypass_disable", nossb_parse_cmdline);
|
|
|
|
|
|
|
|
|
|
static int __init ssb_parse_cmdline(char *str)
|
|
|
|
|
{
|
|
|
|
|
if (!str)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (nossb)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!strcmp(str, "auto"))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_AUTO;
|
|
|
|
|
else if (!strcmp(str, "on"))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_DISABLE;
|
|
|
|
|
else if (!strcmp(str, "off"))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
else if (!strcmp(str, "prctl"))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_PRCTL;
|
|
|
|
|
else if (!strcmp(str, "seccomp"))
|
|
|
|
|
ssb_mode = IS_ENABLED(CONFIG_SECCOMP) ?
|
|
|
|
|
SPEC_STORE_BYPASS_SECCOMP : SPEC_STORE_BYPASS_PRCTL;
|
|
|
|
|
else
|
|
|
|
|
pr_err("Ignoring unknown spec_store_bypass_disable option (%s).\n",
|
|
|
|
|
str);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
early_param("spec_store_bypass_disable", ssb_parse_cmdline);
|
|
|
|
|
|
|
|
|
|
static void __init ssb_select_mitigation(void)
|
|
|
|
|
{
|
|
|
|
|
enum ssb_mitigation_cmd cmd;
|
|
|
|
|
|
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_SSBD))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
cmd = ssb_parse_cmdline();
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS) &&
|
|
|
|
|
(cmd == SPEC_STORE_BYPASS_CMD_NONE ||
|
|
|
|
|
cmd == SPEC_STORE_BYPASS_CMD_AUTO))
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS)) {
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case SPEC_STORE_BYPASS_CMD_SECCOMP:
|
|
|
|
|
/*
|
|
|
|
|
* Choose prctl+seccomp as the default mode if seccomp is
|
|
|
|
|
* enabled.
|
|
|
|
|
*/
|
|
|
|
|
if (IS_ENABLED(CONFIG_SECCOMP))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_SECCOMP;
|
|
|
|
|
else
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_PRCTL;
|
|
|
|
|
break;
|
|
|
|
|
case SPEC_STORE_BYPASS_CMD_ON:
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_DISABLE;
|
|
|
|
|
break;
|
|
|
|
|
case SPEC_STORE_BYPASS_CMD_AUTO:
|
|
|
|
|
if (ssb_mode == SPEC_STORE_BYPASS_AUTO) {
|
|
|
|
|
if (should_mitigate_vuln(X86_BUG_SPEC_STORE_BYPASS))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_PRCTL;
|
|
|
|
|
else
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
break;
|
|
|
|
|
case SPEC_STORE_BYPASS_CMD_PRCTL:
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_PRCTL;
|
|
|
|
|
break;
|
|
|
|
|
case SPEC_STORE_BYPASS_CMD_NONE:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (boot_cpu_has_bug(X86_BUG_SPEC_STORE_BYPASS))
|
|
|
|
|
pr_info("%s\n", ssb_strings[ssb_mode]);
|
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_SSBD))
|
|
|
|
|
ssb_mode = SPEC_STORE_BYPASS_NONE;
|
|
|
|
|
|
|
|
|
|
pr_info("%s\n", ssb_strings[ssb_mode]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init ssb_apply_mitigation(void)
|
|
|
|
|
@@ -2876,6 +2806,7 @@ static int ssb_prctl_get(struct task_struct *task)
|
|
|
|
|
return PR_SPEC_DISABLE;
|
|
|
|
|
case SPEC_STORE_BYPASS_SECCOMP:
|
|
|
|
|
case SPEC_STORE_BYPASS_PRCTL:
|
|
|
|
|
case SPEC_STORE_BYPASS_AUTO:
|
|
|
|
|
if (task_spec_ssb_force_disable(task))
|
|
|
|
|
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
|
|
|
|
|
if (task_spec_ssb_noexec(task))
|
|
|
|
|
@@ -3195,14 +3126,15 @@ ibpb_on_vmexit:
|
|
|
|
|
|
|
|
|
|
static void __init srso_update_mitigation(void)
|
|
|
|
|
{
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_SRSO))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* If retbleed is using IBPB, that works for SRSO as well */
|
|
|
|
|
if (retbleed_mitigation == RETBLEED_MITIGATION_IBPB &&
|
|
|
|
|
boot_cpu_has(X86_FEATURE_IBPB_BRTYPE))
|
|
|
|
|
srso_mitigation = SRSO_MITIGATION_IBPB;
|
|
|
|
|
|
|
|
|
|
if (boot_cpu_has_bug(X86_BUG_SRSO) &&
|
|
|
|
|
!cpu_mitigations_off())
|
|
|
|
|
pr_info("%s\n", srso_strings[srso_mitigation]);
|
|
|
|
|
pr_info("%s\n", srso_strings[srso_mitigation]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init srso_apply_mitigation(void)
|
|
|
|
|
@@ -3304,15 +3236,18 @@ early_param("vmscape", vmscape_parse_cmdline);
|
|
|
|
|
|
|
|
|
|
static void __init vmscape_select_mitigation(void)
|
|
|
|
|
{
|
|
|
|
|
if (cpu_mitigations_off() ||
|
|
|
|
|
!boot_cpu_has_bug(X86_BUG_VMSCAPE) ||
|
|
|
|
|
if (!boot_cpu_has_bug(X86_BUG_VMSCAPE) ||
|
|
|
|
|
!boot_cpu_has(X86_FEATURE_IBPB)) {
|
|
|
|
|
vmscape_mitigation = VMSCAPE_MITIGATION_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vmscape_mitigation == VMSCAPE_MITIGATION_AUTO)
|
|
|
|
|
vmscape_mitigation = VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER;
|
|
|
|
|
if (vmscape_mitigation == VMSCAPE_MITIGATION_AUTO) {
|
|
|
|
|
if (should_mitigate_vuln(X86_BUG_VMSCAPE))
|
|
|
|
|
vmscape_mitigation = VMSCAPE_MITIGATION_IBPB_EXIT_TO_USER;
|
|
|
|
|
else
|
|
|
|
|
vmscape_mitigation = VMSCAPE_MITIGATION_NONE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init vmscape_update_mitigation(void)
|
|
|
|
|
@@ -3626,9 +3561,6 @@ static const char *spectre_bhi_state(void)
|
|
|
|
|
|
|
|
|
|
static ssize_t spectre_v2_show_state(char *buf)
|
|
|
|
|
{
|
|
|
|
|
if (spectre_v2_enabled == SPECTRE_V2_LFENCE)
|
|
|
|
|
return sysfs_emit(buf, "Vulnerable: LFENCE\n");
|
|
|
|
|
|
|
|
|
|
if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
|
|
|
|
|
return sysfs_emit(buf, "Vulnerable: eIBRS with unprivileged eBPF\n");
|
|
|
|
|
|
|
|
|
|
|