|
@@ -566,6 +566,8 @@ void arch_smt_update(void)
|
|
|
case SPECTRE_V2_USER_STRICT:
|
|
|
update_stibp_strict();
|
|
|
break;
|
|
|
+ case SPECTRE_V2_USER_PRCTL:
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&spec_ctrl_mutex);
|
|
@@ -752,12 +754,50 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
|
|
|
+{
|
|
|
+ switch (ctrl) {
|
|
|
+ case PR_SPEC_ENABLE:
|
|
|
+ if (spectre_v2_user == SPECTRE_V2_USER_NONE)
|
|
|
+ return 0;
|
|
|
+ /*
|
|
|
+ * Indirect branch speculation is always disabled in strict
|
|
|
+ * mode.
|
|
|
+ */
|
|
|
+ if (spectre_v2_user == SPECTRE_V2_USER_STRICT)
|
|
|
+ return -EPERM;
|
|
|
+ task_clear_spec_ib_disable(task);
|
|
|
+ task_update_spec_tif(task);
|
|
|
+ break;
|
|
|
+ case PR_SPEC_DISABLE:
|
|
|
+ case PR_SPEC_FORCE_DISABLE:
|
|
|
+ /*
|
|
|
+ * Indirect branch speculation is always allowed when
|
|
|
+ * mitigation is force disabled.
|
|
|
+ */
|
|
|
+ if (spectre_v2_user == SPECTRE_V2_USER_NONE)
|
|
|
+ return -EPERM;
|
|
|
+ if (spectre_v2_user == SPECTRE_V2_USER_STRICT)
|
|
|
+ return 0;
|
|
|
+ task_set_spec_ib_disable(task);
|
|
|
+ if (ctrl == PR_SPEC_FORCE_DISABLE)
|
|
|
+ task_set_spec_ib_force_disable(task);
|
|
|
+ task_update_spec_tif(task);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -ERANGE;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
|
|
|
unsigned long ctrl)
|
|
|
{
|
|
|
switch (which) {
|
|
|
case PR_SPEC_STORE_BYPASS:
|
|
|
return ssb_prctl_set(task, ctrl);
|
|
|
+ case PR_SPEC_INDIRECT_BRANCH:
|
|
|
+ return ib_prctl_set(task, ctrl);
|
|
|
default:
|
|
|
return -ENODEV;
|
|
|
}
|
|
@@ -790,11 +830,34 @@ static int ssb_prctl_get(struct task_struct *task)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int ib_prctl_get(struct task_struct *task)
|
|
|
+{
|
|
|
+ if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
|
|
|
+ return PR_SPEC_NOT_AFFECTED;
|
|
|
+
|
|
|
+ switch (spectre_v2_user) {
|
|
|
+ case SPECTRE_V2_USER_NONE:
|
|
|
+ return PR_SPEC_ENABLE;
|
|
|
+ case SPECTRE_V2_USER_PRCTL:
|
|
|
+ if (task_spec_ib_force_disable(task))
|
|
|
+ return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
|
|
|
+ if (task_spec_ib_disable(task))
|
|
|
+ return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
|
|
|
+ return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
|
|
|
+ case SPECTRE_V2_USER_STRICT:
|
|
|
+ return PR_SPEC_DISABLE;
|
|
|
+ default:
|
|
|
+ return PR_SPEC_NOT_AFFECTED;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
|
|
|
{
|
|
|
switch (which) {
|
|
|
case PR_SPEC_STORE_BYPASS:
|
|
|
return ssb_prctl_get(task);
|
|
|
+ case PR_SPEC_INDIRECT_BRANCH:
|
|
|
+ return ib_prctl_get(task);
|
|
|
default:
|
|
|
return -ENODEV;
|
|
|
}
|
|
@@ -974,6 +1037,8 @@ static char *stibp_state(void)
|
|
|
return ", STIBP: disabled";
|
|
|
case SPECTRE_V2_USER_STRICT:
|
|
|
return ", STIBP: forced";
|
|
|
+ case SPECTRE_V2_USER_PRCTL:
|
|
|
+ return "";
|
|
|
}
|
|
|
return "";
|
|
|
}
|
|
@@ -986,6 +1051,8 @@ static char *ibpb_state(void)
|
|
|
return ", IBPB: disabled";
|
|
|
case SPECTRE_V2_USER_STRICT:
|
|
|
return ", IBPB: always-on";
|
|
|
+ case SPECTRE_V2_USER_PRCTL:
|
|
|
+ return "";
|
|
|
}
|
|
|
}
|
|
|
return "";
|