prctl: Add force disable speculation
commit 356e4bfff2
upstream
For certain use cases it is desired to enforce mitigations so they cannot
be undone afterwards. That's important for loader stubs which want to
prevent a child from disabling the mitigation again. Will also be used for
seccomp(). The extra state preserving of the prctl state for SSB is a
preparatory step for EBPF dymanic speculation control.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
c024722ffe
Коммит
20d036a2e2
|
@ -25,19 +25,21 @@ PR_GET_SPECULATION_CTRL
|
|||
-----------------------
|
||||
|
||||
PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature
|
||||
which is selected with arg2 of prctl(2). The return value uses bits 0-2 with
|
||||
which is selected with arg2 of prctl(2). The return value uses bits 0-3 with
|
||||
the following meaning:
|
||||
|
||||
==== ================ ===================================================
|
||||
==== ===================== ===================================================
|
||||
Bit Define Description
|
||||
==== ================ ===================================================
|
||||
==== ===================== ===================================================
|
||||
0 PR_SPEC_PRCTL Mitigation can be controlled per task by
|
||||
PR_SET_SPECULATION_CTRL
|
||||
1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is
|
||||
disabled
|
||||
2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is
|
||||
enabled
|
||||
==== ================ ===================================================
|
||||
3 PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A
|
||||
subsequent prctl(..., PR_SPEC_ENABLE) will fail.
|
||||
==== ===================== ===================================================
|
||||
|
||||
If all bits are 0 the CPU is not affected by the speculation misfeature.
|
||||
|
||||
|
@ -47,9 +49,11 @@ misfeature will fail.
|
|||
|
||||
PR_SET_SPECULATION_CTRL
|
||||
-----------------------
|
||||
|
||||
PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which
|
||||
is selected by arg2 of :manpage:`prctl(2)` per task. arg3 is used to hand
|
||||
in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE.
|
||||
in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE or
|
||||
PR_SPEC_FORCE_DISABLE.
|
||||
|
||||
Common error codes
|
||||
------------------
|
||||
|
@ -70,10 +74,13 @@ Value Meaning
|
|||
0 Success
|
||||
|
||||
ERANGE arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor
|
||||
PR_SPEC_DISABLE
|
||||
PR_SPEC_DISABLE nor PR_SPEC_FORCE_DISABLE
|
||||
|
||||
ENXIO Control of the selected speculation misfeature is not possible.
|
||||
See PR_GET_SPECULATION_CTRL.
|
||||
|
||||
EPERM Speculation was disabled with PR_SPEC_FORCE_DISABLE and caller
|
||||
tried to enable it again.
|
||||
======= =================================================================
|
||||
|
||||
Speculation misfeature controls
|
||||
|
@ -84,3 +91,4 @@ Speculation misfeature controls
|
|||
* prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0);
|
||||
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0);
|
||||
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0);
|
||||
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0);
|
||||
|
|
|
@ -533,21 +533,37 @@ static void ssb_select_mitigation()
|
|||
|
||||
static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
|
||||
{
|
||||
bool rds = !!test_tsk_thread_flag(task, TIF_RDS);
|
||||
bool update;
|
||||
|
||||
if (ssb_mode != SPEC_STORE_BYPASS_PRCTL)
|
||||
return -ENXIO;
|
||||
|
||||
if (ctrl == PR_SPEC_ENABLE)
|
||||
clear_tsk_thread_flag(task, TIF_RDS);
|
||||
else
|
||||
set_tsk_thread_flag(task, TIF_RDS);
|
||||
switch (ctrl) {
|
||||
case PR_SPEC_ENABLE:
|
||||
/* If speculation is force disabled, enable is not allowed */
|
||||
if (task_spec_ssb_force_disable(task))
|
||||
return -EPERM;
|
||||
task_clear_spec_ssb_disable(task);
|
||||
update = test_and_clear_tsk_thread_flag(task, TIF_RDS);
|
||||
break;
|
||||
case PR_SPEC_DISABLE:
|
||||
task_set_spec_ssb_disable(task);
|
||||
update = !test_and_set_tsk_thread_flag(task, TIF_RDS);
|
||||
break;
|
||||
case PR_SPEC_FORCE_DISABLE:
|
||||
task_set_spec_ssb_disable(task);
|
||||
task_set_spec_ssb_force_disable(task);
|
||||
update = !test_and_set_tsk_thread_flag(task, TIF_RDS);
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If being set on non-current task, delay setting the CPU
|
||||
* mitigation until it is next scheduled.
|
||||
*/
|
||||
if (task == current && rds != !!test_tsk_thread_flag(task, TIF_RDS))
|
||||
if (task == current && update)
|
||||
speculative_store_bypass_update();
|
||||
|
||||
return 0;
|
||||
|
@ -559,7 +575,9 @@ static int ssb_prctl_get(struct task_struct *task)
|
|||
case SPEC_STORE_BYPASS_DISABLE:
|
||||
return PR_SPEC_DISABLE;
|
||||
case SPEC_STORE_BYPASS_PRCTL:
|
||||
if (test_tsk_thread_flag(task, TIF_RDS))
|
||||
if (task_spec_ssb_force_disable(task))
|
||||
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
|
||||
if (task_spec_ssb_disable(task))
|
||||
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
|
||||
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
|
||||
default:
|
||||
|
@ -572,9 +590,6 @@ static int ssb_prctl_get(struct task_struct *task)
|
|||
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
|
||||
unsigned long ctrl)
|
||||
{
|
||||
if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE)
|
||||
return -ERANGE;
|
||||
|
||||
switch (which) {
|
||||
case PR_SPEC_STORE_BYPASS:
|
||||
return ssb_prctl_set(task, ctrl);
|
||||
|
|
|
@ -356,6 +356,9 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
|
|||
case PR_SPEC_NOT_AFFECTED:
|
||||
seq_printf(m, "not vulnerable");
|
||||
break;
|
||||
case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
|
||||
seq_printf(m, "thread force mitigated");
|
||||
break;
|
||||
case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
|
||||
seq_printf(m, "thread mitigated");
|
||||
break;
|
||||
|
|
|
@ -1363,7 +1363,8 @@ static inline bool is_percpu_thread(void)
|
|||
#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */
|
||||
#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */
|
||||
#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */
|
||||
|
||||
#define PFA_SPEC_SSB_DISABLE 3 /* Speculative Store Bypass disabled */
|
||||
#define PFA_SPEC_SSB_FORCE_DISABLE 4 /* Speculative Store Bypass force disabled*/
|
||||
|
||||
#define TASK_PFA_TEST(name, func) \
|
||||
static inline bool task_##func(struct task_struct *p) \
|
||||
|
@ -1388,6 +1389,13 @@ TASK_PFA_TEST(SPREAD_SLAB, spread_slab)
|
|||
TASK_PFA_SET(SPREAD_SLAB, spread_slab)
|
||||
TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab)
|
||||
|
||||
TASK_PFA_TEST(SPEC_SSB_DISABLE, spec_ssb_disable)
|
||||
TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable)
|
||||
TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable)
|
||||
|
||||
TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
|
||||
TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
|
||||
|
||||
static inline void
|
||||
current_restore_flags(unsigned long orig_flags, unsigned long flags)
|
||||
{
|
||||
|
|
|
@ -208,5 +208,6 @@ struct prctl_mm_map {
|
|||
# define PR_SPEC_PRCTL (1UL << 0)
|
||||
# define PR_SPEC_ENABLE (1UL << 1)
|
||||
# define PR_SPEC_DISABLE (1UL << 2)
|
||||
# define PR_SPEC_FORCE_DISABLE (1UL << 3)
|
||||
|
||||
#endif /* _LINUX_PRCTL_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче