Skip to content

Commit 21998a3

Browse files
asteinhaKAGA-KOKO
authored andcommitted
x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced IBRS.
When STIBP is unavailable or enhanced IBRS is available, Linux force-disables the IBPB mitigation of Spectre-BTB even when simultaneous multithreading is disabled. While attempts to enable IBPB using prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, ...) fail with EPERM, the seccomp syscall (or its prctl(PR_SET_SECCOMP, ...) equivalent) which are used e.g. by Chromium or OpenSSH succeed with no errors but the application remains silently vulnerable to cross-process Spectre v2 attacks (classical BTB poisoning). At the same time the SYSFS reporting (/sys/devices/system/cpu/vulnerabilities/spectre_v2) displays that IBPB is conditionally enabled when in fact it is unconditionally disabled. STIBP is useful only when SMT is enabled. When SMT is disabled and STIBP is unavailable, it makes no sense to force-disable also IBPB, because IBPB protects against cross-process Spectre-BTB attacks regardless of the SMT state. At the same time since missing STIBP was only observed on AMD CPUs, AMD does not recommend using STIBP, but recommends using IBPB, so disabling IBPB because of missing STIBP goes directly against AMD's advice: https://developer.amd.com/wp-content/resources/Architecture_Guidelines_Update_Indirect_Branch_Control.pdf Similarly, enhanced IBRS is designed to protect cross-core BTB poisoning and BTB-poisoning attacks from user space against kernel (and BTB-poisoning attacks from guest against hypervisor), it is not designed to prevent cross-process (or cross-VM) BTB poisoning between processes (or VMs) running on the same core. Therefore, even with enhanced IBRS it is necessary to flush the BTB during context-switches, so there is no reason to force disable IBPB when enhanced IBRS is available. Enable the prctl control of IBPB even when STIBP is unavailable or enhanced IBRS is available. Fixes: 7cc765a ("x86/speculation: Enable prctl mode for spectre_v2_user") Signed-off-by: Anthony Steinhauser <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected]
1 parent be25d1b commit 21998a3

File tree

1 file changed

+50
-37
lines changed

1 file changed

+50
-37
lines changed

arch/x86/kernel/cpu/bugs.c

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,9 @@ early_param("nospectre_v1", nospectre_v1_cmdline);
495495
static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
496496
SPECTRE_V2_NONE;
497497

498-
static enum spectre_v2_user_mitigation spectre_v2_user __ro_after_init =
498+
static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
499+
SPECTRE_V2_USER_NONE;
500+
static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
499501
SPECTRE_V2_USER_NONE;
500502

501503
#ifdef CONFIG_RETPOLINE
@@ -641,15 +643,6 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
641643
break;
642644
}
643645

644-
/*
645-
* At this point, an STIBP mode other than "off" has been set.
646-
* If STIBP support is not being forced, check if STIBP always-on
647-
* is preferred.
648-
*/
649-
if (mode != SPECTRE_V2_USER_STRICT &&
650-
boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
651-
mode = SPECTRE_V2_USER_STRICT_PREFERRED;
652-
653646
/* Initialize Indirect Branch Prediction Barrier */
654647
if (boot_cpu_has(X86_FEATURE_IBPB)) {
655648
setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
@@ -672,23 +665,36 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
672665
pr_info("mitigation: Enabling %s Indirect Branch Prediction Barrier\n",
673666
static_key_enabled(&switch_mm_always_ibpb) ?
674667
"always-on" : "conditional");
668+
669+
spectre_v2_user_ibpb = mode;
675670
}
676671

677-
/* If enhanced IBRS is enabled no STIBP required */
678-
if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
672+
/*
673+
* If enhanced IBRS is enabled or SMT impossible, STIBP is not
674+
* required.
675+
*/
676+
if (!smt_possible || spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
679677
return;
680678

681679
/*
682-
* If SMT is not possible or STIBP is not available clear the STIBP
683-
* mode.
680+
* At this point, an STIBP mode other than "off" has been set.
681+
* If STIBP support is not being forced, check if STIBP always-on
682+
* is preferred.
683+
*/
684+
if (mode != SPECTRE_V2_USER_STRICT &&
685+
boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
686+
mode = SPECTRE_V2_USER_STRICT_PREFERRED;
687+
688+
/*
689+
* If STIBP is not available, clear the STIBP mode.
684690
*/
685-
if (!smt_possible || !boot_cpu_has(X86_FEATURE_STIBP))
691+
if (!boot_cpu_has(X86_FEATURE_STIBP))
686692
mode = SPECTRE_V2_USER_NONE;
693+
694+
spectre_v2_user_stibp = mode;
695+
687696
set_mode:
688-
spectre_v2_user = mode;
689-
/* Only print the STIBP mode when SMT possible */
690-
if (smt_possible)
691-
pr_info("%s\n", spectre_v2_user_strings[mode]);
697+
pr_info("%s\n", spectre_v2_user_strings[mode]);
692698
}
693699

694700
static const char * const spectre_v2_strings[] = {
@@ -921,7 +927,7 @@ void cpu_bugs_smt_update(void)
921927
{
922928
mutex_lock(&spec_ctrl_mutex);
923929

924-
switch (spectre_v2_user) {
930+
switch (spectre_v2_user_stibp) {
925931
case SPECTRE_V2_USER_NONE:
926932
break;
927933
case SPECTRE_V2_USER_STRICT:
@@ -1164,14 +1170,16 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
11641170
{
11651171
switch (ctrl) {
11661172
case PR_SPEC_ENABLE:
1167-
if (spectre_v2_user == SPECTRE_V2_USER_NONE)
1173+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
1174+
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
11681175
return 0;
11691176
/*
11701177
* Indirect branch speculation is always disabled in strict
11711178
* mode.
11721179
*/
1173-
if (spectre_v2_user == SPECTRE_V2_USER_STRICT ||
1174-
spectre_v2_user == SPECTRE_V2_USER_STRICT_PREFERRED)
1180+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1181+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1182+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
11751183
return -EPERM;
11761184
task_clear_spec_ib_disable(task);
11771185
task_update_spec_tif(task);
@@ -1182,10 +1190,12 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
11821190
* Indirect branch speculation is always allowed when
11831191
* mitigation is force disabled.
11841192
*/
1185-
if (spectre_v2_user == SPECTRE_V2_USER_NONE)
1193+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
1194+
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
11861195
return -EPERM;
1187-
if (spectre_v2_user == SPECTRE_V2_USER_STRICT ||
1188-
spectre_v2_user == SPECTRE_V2_USER_STRICT_PREFERRED)
1196+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1197+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1198+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
11891199
return 0;
11901200
task_set_spec_ib_disable(task);
11911201
if (ctrl == PR_SPEC_FORCE_DISABLE)
@@ -1216,7 +1226,8 @@ void arch_seccomp_spec_mitigate(struct task_struct *task)
12161226
{
12171227
if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP)
12181228
ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE);
1219-
if (spectre_v2_user == SPECTRE_V2_USER_SECCOMP)
1229+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
1230+
spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP)
12201231
ib_prctl_set(task, PR_SPEC_FORCE_DISABLE);
12211232
}
12221233
#endif
@@ -1247,22 +1258,24 @@ static int ib_prctl_get(struct task_struct *task)
12471258
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
12481259
return PR_SPEC_NOT_AFFECTED;
12491260

1250-
switch (spectre_v2_user) {
1251-
case SPECTRE_V2_USER_NONE:
1261+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
1262+
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
12521263
return PR_SPEC_ENABLE;
1253-
case SPECTRE_V2_USER_PRCTL:
1254-
case SPECTRE_V2_USER_SECCOMP:
1264+
else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1265+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1266+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
1267+
return PR_SPEC_DISABLE;
1268+
else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
1269+
spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
1270+
spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
1271+
spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP) {
12551272
if (task_spec_ib_force_disable(task))
12561273
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
12571274
if (task_spec_ib_disable(task))
12581275
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
12591276
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
1260-
case SPECTRE_V2_USER_STRICT:
1261-
case SPECTRE_V2_USER_STRICT_PREFERRED:
1262-
return PR_SPEC_DISABLE;
1263-
default:
1277+
} else
12641278
return PR_SPEC_NOT_AFFECTED;
1265-
}
12661279
}
12671280

12681281
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
@@ -1501,7 +1514,7 @@ static char *stibp_state(void)
15011514
if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
15021515
return "";
15031516

1504-
switch (spectre_v2_user) {
1517+
switch (spectre_v2_user_stibp) {
15051518
case SPECTRE_V2_USER_NONE:
15061519
return ", STIBP: disabled";
15071520
case SPECTRE_V2_USER_STRICT:

0 commit comments

Comments
 (0)