Commit 19c24f7e authored by David Kaplan's avatar David Kaplan Committed by Borislav Petkov (AMD)
Browse files

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: default avatarDavid Kaplan <david.kaplan@amd.com>
Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/20250707183316.1349127-3-david.kaplan@amd.com
parent 1caa1b05
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -198,9 +198,25 @@ void cpuhp_report_idle_dead(void);
static inline void cpuhp_report_idle_dead(void) { }
#endif /* #ifdef CONFIG_HOTPLUG_CPU */

enum cpu_attack_vectors {
	CPU_MITIGATE_USER_KERNEL,
	CPU_MITIGATE_USER_USER,
	CPU_MITIGATE_GUEST_HOST,
	CPU_MITIGATE_GUEST_GUEST,
	NR_CPU_ATTACK_VECTORS,
};

enum smt_mitigations {
	SMT_MITIGATIONS_OFF,
	SMT_MITIGATIONS_AUTO,
	SMT_MITIGATIONS_ON,
};

#ifdef CONFIG_CPU_MITIGATIONS
extern bool cpu_mitigations_off(void);
extern bool cpu_mitigations_auto_nosmt(void);
extern bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v);
extern enum smt_mitigations smt_mitigations;
#else
static inline bool cpu_mitigations_off(void)
{
@@ -210,6 +226,11 @@ static inline bool cpu_mitigations_auto_nosmt(void)
{
	return false;
}
static inline bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v)
{
	return false;
}
#define smt_mitigations SMT_MITIGATIONS_OFF
#endif

#endif /* _LINUX_CPU_H_ */
+119 −11
Original line number Diff line number Diff line
@@ -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;
}