Skip to content

Commit 91bce76

Browse files
asteinhaSomasundaram Krishnasamy
authored andcommitted
x86/speculation: Avoid force-disabling IBPB based on STIBP and enhanced IBRS.
[ Upstream commit 21998a3 ] 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] Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit b4eba1edf71e3ce882d79fd46d654770a7b277b0) Orabug: 31557804 CVE: CVE-2020-10767 Signed-off-by: Sherry Yang <[email protected]> Conflicts: arch/x86/kernel/cpu/bugs.c Reviewed-by: John Donnelly <[email protected]> Signed-off-by: Somasundaram Krishnasamy <[email protected]>
1 parent a885496 commit 91bce76

File tree

1 file changed

+51
-40
lines changed

1 file changed

+51
-40
lines changed

arch/x86/kernel/cpu/bugs.c

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -880,8 +880,10 @@ early_param("nospectre_v1", nospectre_v1_cmdline);
880880
#undef pr_fmt
881881
#define pr_fmt(fmt) "Spectre V2 : " fmt
882882

883-
static enum spectre_v2_user_mitigation spectre_v2_user =
884-
SPECTRE_V2_USER_NONE;
883+
static enum spectre_v2_user_mitigation spectre_v2_user_stibp =
884+
SPECTRE_V2_USER_NONE;
885+
static enum spectre_v2_user_mitigation spectre_v2_user_ibpb =
886+
SPECTRE_V2_USER_NONE;
885887

886888
#ifdef CONFIG_RETPOLINE
887889
static bool spectre_v2_bad_module;
@@ -1090,19 +1092,8 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
10901092
break;
10911093
}
10921094

1093-
/*
1094-
* At this point, an STIBP mode other than "off" has been set.
1095-
* If STIBP support is not being forced, check if STIBP always-on
1096-
* is preferred.
1097-
*/
1098-
if (mode != SPECTRE_V2_USER_STRICT &&
1099-
boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
1100-
mode = SPECTRE_V2_USER_STRICT_PREFERRED;
1101-
1102-
11031095
/* Initialize Indirect Branch Prediction Barrier if supported */
11041096
if (boot_cpu_has(X86_FEATURE_IBPB) && use_ibpb) {
1105-
11061097
switch (cmd) {
11071098
case SPECTRE_V2_USER_CMD_FORCE:
11081099
case SPECTRE_V2_USER_CMD_PRCTL_IBPB:
@@ -1121,23 +1112,36 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
11211112
pr_info("mitigation: Enabling %s Indirect Branch Prediction Barrier\n",
11221113
static_key_enabled(&switch_mm_always_ibpb) ?
11231114
"always-on" : "conditional");
1115+
1116+
spectre_v2_user_ibpb = mode;
11241117
}
11251118

1126-
/* If enhanced IBRS is enabled no STIPB required */
1127-
if (spectre_v2_eibrs_enabled())
1119+
/*
1120+
* If enhanced IBRS is enabled or SMT impossible, STIBP is not
1121+
* required.
1122+
*/
1123+
if (!smt_possible || spectre_v2_eibrs_enabled())
11281124
return;
11291125

11301126
/*
1131-
* If SMT is not possible or STIBP is not available clear the STIPB
1132-
* mode.
1127+
* At this point, an STIBP mode other than "off" has been set.
1128+
* If STIBP support is not being forced, check if STIBP always-on
1129+
* is preferred.
1130+
*/
1131+
if (mode != SPECTRE_V2_USER_STRICT &&
1132+
boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
1133+
mode = SPECTRE_V2_USER_STRICT_PREFERRED;
1134+
1135+
/*
1136+
* If STIBP is not available, clear the STIBP mode.
11331137
*/
1134-
if (!smt_possible || !boot_cpu_has(X86_FEATURE_STIBP))
1138+
if (!boot_cpu_has(X86_FEATURE_STIBP))
11351139
mode = SPECTRE_V2_USER_NONE;
1140+
1141+
spectre_v2_user_stibp = mode;
1142+
11361143
set_mode:
1137-
spectre_v2_user = mode;
1138-
/* Only print the STIBP mode when SMT possible */
1139-
if (smt_possible)
1140-
pr_info("%s\n", spectre_v2_user_strings[mode]);
1144+
pr_info("%s\n", spectre_v2_user_strings[mode]);
11411145
}
11421146

11431147
static const char * const spectre_v2_strings[] = {
@@ -1543,7 +1547,7 @@ void arch_smt_update(void)
15431547
{
15441548
mutex_lock(&spec_ctrl_mutex);
15451549

1546-
switch (spectre_v2_user) {
1550+
switch (spectre_v2_user_stibp) {
15471551
case SPECTRE_V2_USER_NONE:
15481552
break;
15491553
case SPECTRE_V2_USER_STRICT:
@@ -1793,14 +1797,16 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
17931797
{
17941798
switch (ctrl) {
17951799
case PR_SPEC_ENABLE:
1796-
if (spectre_v2_user == SPECTRE_V2_USER_NONE)
1800+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
1801+
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
17971802
return 0;
17981803
/*
17991804
* Indirect branch speculation is always disabled in strict
18001805
* mode.
18011806
*/
1802-
if (spectre_v2_user == SPECTRE_V2_USER_STRICT ||
1803-
spectre_v2_user == SPECTRE_V2_USER_STRICT_PREFERRED)
1807+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1808+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1809+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
18041810
return -EPERM;
18051811
task_clear_spec_ib_disable(task);
18061812
task_update_spec_tif(task);
@@ -1811,10 +1817,12 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
18111817
* Indirect branch speculation is always allowed when
18121818
* mitigation is force disabled.
18131819
*/
1814-
if (spectre_v2_user == SPECTRE_V2_USER_NONE)
1820+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
1821+
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
18151822
return -EPERM;
1816-
if (spectre_v2_user == SPECTRE_V2_USER_STRICT ||
1817-
spectre_v2_user == SPECTRE_V2_USER_STRICT_PREFERRED)
1823+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1824+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1825+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
18181826
return 0;
18191827
task_set_spec_ib_disable(task);
18201828
if (ctrl == PR_SPEC_FORCE_DISABLE)
@@ -1845,7 +1853,8 @@ void arch_seccomp_spec_mitigate(struct task_struct *task)
18451853
{
18461854
if (ssb_mode == SPEC_STORE_BYPASS_SECCOMP)
18471855
ssb_prctl_set(task, PR_SPEC_FORCE_DISABLE);
1848-
if (spectre_v2_user == SPECTRE_V2_USER_SECCOMP)
1856+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
1857+
spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP)
18491858
ib_prctl_set(task, PR_SPEC_FORCE_DISABLE);
18501859
}
18511860
#endif
@@ -1874,22 +1883,24 @@ static int ib_prctl_get(struct task_struct *task)
18741883
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
18751884
return PR_SPEC_NOT_AFFECTED;
18761885

1877-
switch (spectre_v2_user) {
1878-
case SPECTRE_V2_USER_NONE:
1886+
if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
1887+
spectre_v2_user_stibp == SPECTRE_V2_USER_NONE)
18791888
return PR_SPEC_ENABLE;
1880-
case SPECTRE_V2_USER_PRCTL:
1881-
case SPECTRE_V2_USER_SECCOMP:
1889+
else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1890+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1891+
spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED)
1892+
return PR_SPEC_DISABLE;
1893+
else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
1894+
spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
1895+
spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
1896+
spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP) {
18821897
if (task_spec_ib_force_disable(task))
18831898
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
18841899
if (task_spec_ib_disable(task))
18851900
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
18861901
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
1887-
case SPECTRE_V2_USER_STRICT:
1888-
case SPECTRE_V2_USER_STRICT_PREFERRED:
1889-
return PR_SPEC_DISABLE;
1890-
default:
1902+
} else
18911903
return PR_SPEC_NOT_AFFECTED;
1892-
}
18931904
}
18941905

18951906
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
@@ -2127,7 +2138,7 @@ static char *stibp_state(void)
21272138
if (spectre_v2_eibrs_enabled())
21282139
return "";
21292140

2130-
switch (spectre_v2_user) {
2141+
switch (spectre_v2_user_stibp) {
21312142
case SPECTRE_V2_USER_NONE:
21322143
return ", STIBP: disabled";
21332144
case SPECTRE_V2_USER_STRICT:

0 commit comments

Comments
 (0)