@@ -1252,24 +1252,41 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
12521252 return 0 ;
12531253}
12541254
1255+ static bool is_spec_ib_user_controlled (void )
1256+ {
1257+ return spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
1258+ spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
1259+ spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
1260+ spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP ;
1261+ }
1262+
12551263static int ib_prctl_set (struct task_struct * task , unsigned long ctrl )
12561264{
12571265 switch (ctrl ) {
12581266 case PR_SPEC_ENABLE :
12591267 if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
12601268 spectre_v2_user_stibp == SPECTRE_V2_USER_NONE )
12611269 return 0 ;
1262- /*
1263- * Indirect branch speculation is always disabled in strict
1264- * mode. It can neither be enabled if it was force-disabled
1265- * by a previous prctl call.
12661270
1271+ /*
1272+ * With strict mode for both IBPB and STIBP, the instruction
1273+ * code paths avoid checking this task flag and instead,
1274+ * unconditionally run the instruction. However, STIBP and IBPB
1275+ * are independent and either can be set to conditionally
1276+ * enabled regardless of the mode of the other.
1277+ *
1278+ * If either is set to conditional, allow the task flag to be
1279+ * updated, unless it was force-disabled by a previous prctl
1280+ * call. Currently, this is possible on an AMD CPU which has the
1281+ * feature X86_FEATURE_AMD_STIBP_ALWAYS_ON. In this case, if the
1282+ * kernel is booted with 'spectre_v2_user=seccomp', then
1283+ * spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP and
1284+ * spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED.
12671285 */
1268- if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1269- spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1270- spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ||
1286+ if (!is_spec_ib_user_controlled () ||
12711287 task_spec_ib_force_disable (task ))
12721288 return - EPERM ;
1289+
12731290 task_clear_spec_ib_disable (task );
12741291 task_update_spec_tif (task );
12751292 break ;
@@ -1282,10 +1299,10 @@ static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
12821299 if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
12831300 spectre_v2_user_stibp == SPECTRE_V2_USER_NONE )
12841301 return - EPERM ;
1285- if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1286- spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1287- spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED )
1302+
1303+ if (!is_spec_ib_user_controlled ())
12881304 return 0 ;
1305+
12891306 task_set_spec_ib_disable (task );
12901307 if (ctrl == PR_SPEC_FORCE_DISABLE )
12911308 task_set_spec_ib_force_disable (task );
@@ -1350,20 +1367,17 @@ static int ib_prctl_get(struct task_struct *task)
13501367 if (spectre_v2_user_ibpb == SPECTRE_V2_USER_NONE &&
13511368 spectre_v2_user_stibp == SPECTRE_V2_USER_NONE )
13521369 return PR_SPEC_ENABLE ;
1353- else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1354- spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1355- spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED )
1356- return PR_SPEC_DISABLE ;
1357- else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_PRCTL ||
1358- spectre_v2_user_ibpb == SPECTRE_V2_USER_SECCOMP ||
1359- spectre_v2_user_stibp == SPECTRE_V2_USER_PRCTL ||
1360- spectre_v2_user_stibp == SPECTRE_V2_USER_SECCOMP ) {
1370+ else if (is_spec_ib_user_controlled ()) {
13611371 if (task_spec_ib_force_disable (task ))
13621372 return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE ;
13631373 if (task_spec_ib_disable (task ))
13641374 return PR_SPEC_PRCTL | PR_SPEC_DISABLE ;
13651375 return PR_SPEC_PRCTL | PR_SPEC_ENABLE ;
1366- } else
1376+ } else if (spectre_v2_user_ibpb == SPECTRE_V2_USER_STRICT ||
1377+ spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
1378+ spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED )
1379+ return PR_SPEC_DISABLE ;
1380+ else
13671381 return PR_SPEC_NOT_AFFECTED ;
13681382}
13691383
0 commit comments