mirror of https://gitee.com/openkylin/linux.git
prctl: Add force disable speculation
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>
This commit is contained in:
parent
f9544b2b07
commit
356e4bfff2
|
@ -25,19 +25,21 @@ PR_GET_SPECULATION_CTRL
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature
|
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:
|
the following meaning:
|
||||||
|
|
||||||
==== ================ ===================================================
|
==== ===================== ===================================================
|
||||||
Bit Define Description
|
Bit Define Description
|
||||||
==== ================ ===================================================
|
==== ===================== ===================================================
|
||||||
0 PR_SPEC_PRCTL Mitigation can be controlled per task by
|
0 PR_SPEC_PRCTL Mitigation can be controlled per task by
|
||||||
PR_SET_SPECULATION_CTRL
|
PR_SET_SPECULATION_CTRL
|
||||||
1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is
|
1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is
|
||||||
disabled
|
disabled
|
||||||
2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is
|
2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is
|
||||||
enabled
|
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.
|
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
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which
|
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
|
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
|
Common error codes
|
||||||
------------------
|
------------------
|
||||||
|
@ -70,10 +74,13 @@ Value Meaning
|
||||||
0 Success
|
0 Success
|
||||||
|
|
||||||
ERANGE arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor
|
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.
|
ENXIO Control of the selected speculation misfeature is not possible.
|
||||||
See PR_GET_SPECULATION_CTRL.
|
See PR_GET_SPECULATION_CTRL.
|
||||||
|
|
||||||
|
EPERM Speculation was disabled with PR_SPEC_FORCE_DISABLE and caller
|
||||||
|
tried to enable it again.
|
||||||
======= =================================================================
|
======= =================================================================
|
||||||
|
|
||||||
Speculation misfeature controls
|
Speculation misfeature controls
|
||||||
|
@ -84,3 +91,4 @@ Speculation misfeature controls
|
||||||
* prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0);
|
* 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_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_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)
|
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)
|
if (ssb_mode != SPEC_STORE_BYPASS_PRCTL)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
if (ctrl == PR_SPEC_ENABLE)
|
switch (ctrl) {
|
||||||
clear_tsk_thread_flag(task, TIF_RDS);
|
case PR_SPEC_ENABLE:
|
||||||
else
|
/* If speculation is force disabled, enable is not allowed */
|
||||||
set_tsk_thread_flag(task, TIF_RDS);
|
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
|
* If being set on non-current task, delay setting the CPU
|
||||||
* mitigation until it is next scheduled.
|
* 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();
|
speculative_store_bypass_update();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -559,7 +575,9 @@ static int ssb_prctl_get(struct task_struct *task)
|
||||||
case SPEC_STORE_BYPASS_DISABLE:
|
case SPEC_STORE_BYPASS_DISABLE:
|
||||||
return PR_SPEC_DISABLE;
|
return PR_SPEC_DISABLE;
|
||||||
case SPEC_STORE_BYPASS_PRCTL:
|
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_DISABLE;
|
||||||
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
|
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
|
||||||
default:
|
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,
|
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
|
||||||
unsigned long ctrl)
|
unsigned long ctrl)
|
||||||
{
|
{
|
||||||
if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE)
|
|
||||||
return -ERANGE;
|
|
||||||
|
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case PR_SPEC_STORE_BYPASS:
|
case PR_SPEC_STORE_BYPASS:
|
||||||
return ssb_prctl_set(task, ctrl);
|
return ssb_prctl_set(task, ctrl);
|
||||||
|
|
|
@ -344,6 +344,9 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
|
||||||
case PR_SPEC_NOT_AFFECTED:
|
case PR_SPEC_NOT_AFFECTED:
|
||||||
seq_printf(m, "not vulnerable");
|
seq_printf(m, "not vulnerable");
|
||||||
break;
|
break;
|
||||||
|
case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
|
||||||
|
seq_printf(m, "thread force mitigated");
|
||||||
|
break;
|
||||||
case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
|
case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
|
||||||
seq_printf(m, "thread mitigated");
|
seq_printf(m, "thread mitigated");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1393,7 +1393,8 @@ static inline bool is_percpu_thread(void)
|
||||||
#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */
|
#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */
|
||||||
#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */
|
#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */
|
||||||
#define PFA_SPREAD_SLAB 2 /* Spread some slab caches 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) \
|
#define TASK_PFA_TEST(name, func) \
|
||||||
static inline bool task_##func(struct task_struct *p) \
|
static inline bool task_##func(struct task_struct *p) \
|
||||||
|
@ -1418,6 +1419,13 @@ TASK_PFA_TEST(SPREAD_SLAB, spread_slab)
|
||||||
TASK_PFA_SET(SPREAD_SLAB, spread_slab)
|
TASK_PFA_SET(SPREAD_SLAB, spread_slab)
|
||||||
TASK_PFA_CLEAR(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
|
static inline void
|
||||||
current_restore_flags(unsigned long orig_flags, unsigned long flags)
|
current_restore_flags(unsigned long orig_flags, unsigned long flags)
|
||||||
{
|
{
|
||||||
|
|
|
@ -217,5 +217,6 @@ struct prctl_mm_map {
|
||||||
# define PR_SPEC_PRCTL (1UL << 0)
|
# define PR_SPEC_PRCTL (1UL << 0)
|
||||||
# define PR_SPEC_ENABLE (1UL << 1)
|
# define PR_SPEC_ENABLE (1UL << 1)
|
||||||
# define PR_SPEC_DISABLE (1UL << 2)
|
# define PR_SPEC_DISABLE (1UL << 2)
|
||||||
|
# define PR_SPEC_FORCE_DISABLE (1UL << 3)
|
||||||
|
|
||||||
#endif /* _LINUX_PRCTL_H */
|
#endif /* _LINUX_PRCTL_H */
|
||||||
|
|
Loading…
Reference in New Issue