Skip to content

Commit

Permalink
prctl: Add force disable speculation
Browse files Browse the repository at this point in the history
commit 356e4bf 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 <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
KAGA-KOKO authored and gregkh committed May 22, 2018
1 parent c024722 commit 20d036a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 24 deletions.
34 changes: 21 additions & 13 deletions Documentation/userspace-api/spec_ctrl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
==== ================ ===================================================
==== ===================== ===================================================
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.

Expand All @@ -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
------------------
Expand All @@ -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
Expand All @@ -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);
35 changes: 25 additions & 10 deletions arch/x86/kernel/cpu/bugs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions fs/proc/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 9 additions & 1 deletion include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand All @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 20d036a

Please sign in to comment.