cpu: Define attack vectors

Define 4 new attack vectors that are used for controlling CPU speculation
mitigations.  These may be individually disabled as part of the
mitigations= command line.  Attack vector controls are combined with global
options like 'auto' or 'auto,nosmt' like 'mitigations=auto,no_user_kernel'.
The global options come first in the mitigations= string.

Cross-thread mitigations can either remain enabled fully, including
potentially disabling SMT ('auto,nosmt'), remain enabled except for
disabling SMT ('auto'), or entirely disabled through the new
'no_cross_thread' attack vector option.

The default settings for these attack vectors are consistent with existing
kernel defaults, other than the automatic disabling of VM-based attack
vectors if KVM support is not present.

Signed-off-by: David Kaplan <david.kaplan@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/20250707183316.1349127-3-david.kaplan@amd.com
This commit is contained in:
David Kaplan authored and Borislav Petkov (AMD) committed 2025-07-11 17:55:16 +02:00
1 parent 1caa1b0509
commit 19c24f7ee3
2 files changed
+140 -11

No files matched your search

+119 -11
View File
@@ -37,6 +37,7 @@
#include <linux/cpuset.h>
#include <linux/random.h>
#include <linux/cc_platform.h>
#include <linux/parser.h>
#include <trace/events/power.h>
#define CREATE_TRACE_POINTS
@@ -3174,8 +3175,38 @@ void __init boot_cpu_hotplug_init(void)
#ifdef CONFIG_CPU_MITIGATIONS
/*
* These are used for a global "mitigations=" cmdline option for toggling
* optional CPU mitigations.
* All except the cross-thread attack vector are mitigated by default.
* Cross-thread mitigation often requires disabling SMT which is expensive
* so cross-thread mitigations are only partially enabled by default.
*
* Guest-to-Host and Guest-to-Guest vectors are only needed if KVM support is
* present.
*/
static bool attack_vectors[NR_CPU_ATTACK_VECTORS] __ro_after_init = {
[CPU_MITIGATE_USER_KERNEL] = true,
[CPU_MITIGATE_USER_USER] = true,
[CPU_MITIGATE_GUEST_HOST] = IS_ENABLED(CONFIG_KVM),
[CPU_MITIGATE_GUEST_GUEST] = IS_ENABLED(CONFIG_KVM),
};
bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v)
{
if (v < NR_CPU_ATTACK_VECTORS)
return attack_vectors[v];
WARN_ONCE(1, "Invalid attack vector %d\n", v);
return false;
}
/*
* There are 3 global options, 'off', 'auto', 'auto,nosmt'. These may optionally
* be combined with attack-vector disables which follow them.
*
* Examples:
* mitigations=auto,no_user_kernel,no_user_user,no_cross_thread
* mitigations=auto,nosmt,no_guest_host,no_guest_guest
*
* mitigations=off is equivalent to disabling all attack vectors.
*/
enum cpu_mitigations {
CPU_MITIGATIONS_OFF,
@@ -3183,19 +3214,96 @@ enum cpu_mitigations {
CPU_MITIGATIONS_AUTO_NOSMT,
};
enum {
NO_USER_KERNEL,
NO_USER_USER,
NO_GUEST_HOST,
NO_GUEST_GUEST,
NO_CROSS_THREAD,
NR_VECTOR_PARAMS,
};
enum smt_mitigations smt_mitigations __ro_after_init = SMT_MITIGATIONS_AUTO;
static enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO;
static const match_table_t global_mitigations = {
{ CPU_MITIGATIONS_AUTO_NOSMT, "auto,nosmt"},
{ CPU_MITIGATIONS_AUTO, "auto"},
{ CPU_MITIGATIONS_OFF, "off"},
};
static const match_table_t vector_mitigations = {
{ NO_USER_KERNEL, "no_user_kernel"},
{ NO_USER_USER, "no_user_user"},
{ NO_GUEST_HOST, "no_guest_host"},
{ NO_GUEST_GUEST, "no_guest_guest"},
{ NO_CROSS_THREAD, "no_cross_thread"},
{ NR_VECTOR_PARAMS, NULL},
};
static int __init mitigations_parse_global_opt(char *arg)
{
int i;
for (i = 0; i < ARRAY_SIZE(global_mitigations); i++) {
const char *pattern = global_mitigations[i].pattern;
if (!strncmp(arg, pattern, strlen(pattern))) {
cpu_mitigations = global_mitigations[i].token;
return strlen(pattern);
}
}
return 0;
}
static int __init mitigations_parse_cmdline(char *arg)
{
if (!strcmp(arg, "off"))
cpu_mitigations = CPU_MITIGATIONS_OFF;
else if (!strcmp(arg, "auto"))
cpu_mitigations = CPU_MITIGATIONS_AUTO;
else if (!strcmp(arg, "auto,nosmt"))
cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT;
else
pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n",
arg);
char *s, *p;
int len;
len = mitigations_parse_global_opt(arg);
if (cpu_mitigations_off()) {
memset(attack_vectors, 0, sizeof(attack_vectors));
smt_mitigations = SMT_MITIGATIONS_OFF;
} else if (cpu_mitigations_auto_nosmt()) {
smt_mitigations = SMT_MITIGATIONS_ON;
}
p = arg + len;
if (!*p)
return 0;
/* Attack vector controls may come after the ',' */
if (*p++ != ',' || !IS_ENABLED(CONFIG_ARCH_HAS_CPU_ATTACK_VECTORS)) {
pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n", arg);
return 0;
}
while ((s = strsep(&p, ",")) != NULL) {
switch (match_token(s, vector_mitigations, NULL)) {
case NO_USER_KERNEL:
attack_vectors[CPU_MITIGATE_USER_KERNEL] = false;
break;
case NO_USER_USER:
attack_vectors[CPU_MITIGATE_USER_USER] = false;
break;
case NO_GUEST_HOST:
attack_vectors[CPU_MITIGATE_GUEST_HOST] = false;
break;
case NO_GUEST_GUEST:
attack_vectors[CPU_MITIGATE_GUEST_GUEST] = false;
break;
case NO_CROSS_THREAD:
smt_mitigations = SMT_MITIGATIONS_OFF;
break;
default:
pr_crit("Unsupported mitigations options %s\n", s);
return 0;
}
}
return 0;
}