Commit 356e4bff authored by Thomas Gleixner's avatar Thomas Gleixner

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: default avatarThomas Gleixner <tglx@linutronix.de>
parent f9544b2b
...@@ -25,19 +25,21 @@ PR_GET_SPECULATION_CTRL ...@@ -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. ...@@ -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 ...@@ -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 ...@@ -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() ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment