Skip to content

Commit c1a80db

Browse files
KAGA-KOKOkonradwilk
authored andcommitted
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 <[email protected]> (cherry picked from commit 356e4bf) Orabug: 28034177 CVE: CVE-2018-3639 Signed-off-by: Konrad Rzeszutek Wilk <[email protected]> Tested-by: Mihai Carabas <[email protected]> Reviewed-by: Mihai Carabas <[email protected]> Reviewed-by: John Haxby <[email protected]>
1 parent e439465 commit c1a80db

File tree

5 files changed

+59
-24
lines changed

5 files changed

+59
-24
lines changed

Documentation/userspace-api/spec_ctrl.rst

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,21 @@ PR_GET_SPECULATION_CTRL
2525
-----------------------
2626

2727
PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature
28-
which is selected with arg2 of prctl(2). The return value uses bits 0-2 with
28+
which is selected with arg2 of prctl(2). The return value uses bits 0-3 with
2929
the following meaning:
3030

31-
==== ================ ===================================================
32-
Bit Define Description
33-
==== ================ ===================================================
34-
0 PR_SPEC_PRCTL Mitigation can be controlled per task by
35-
PR_SET_SPECULATION_CTRL
36-
1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is
37-
disabled
38-
2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is
39-
enabled
40-
==== ================ ===================================================
31+
==== ===================== ===================================================
32+
Bit Define Description
33+
==== ===================== ===================================================
34+
0 PR_SPEC_PRCTL Mitigation can be controlled per task by
35+
PR_SET_SPECULATION_CTRL
36+
1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is
37+
disabled
38+
2 PR_SPEC_DISABLE The speculation feature is disabled, mitigation is
39+
enabled
40+
3 PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A
41+
subsequent prctl(..., PR_SPEC_ENABLE) will fail.
42+
==== ===================== ===================================================
4143

4244
If all bits are 0 the CPU is not affected by the speculation misfeature.
4345

@@ -47,9 +49,11 @@ misfeature will fail.
4749

4850
PR_SET_SPECULATION_CTRL
4951
-----------------------
52+
5053
PR_SET_SPECULATION_CTRL allows to control the speculation misfeature, which
5154
is selected by arg2 of :manpage:`prctl(2)` per task. arg3 is used to hand
52-
in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE.
55+
in the control value, i.e. either PR_SPEC_ENABLE or PR_SPEC_DISABLE or
56+
PR_SPEC_FORCE_DISABLE.
5357

5458
Common error codes
5559
------------------
@@ -70,10 +74,13 @@ Value Meaning
7074
0 Success
7175

7276
ERANGE arg3 is incorrect, i.e. it's neither PR_SPEC_ENABLE nor
73-
PR_SPEC_DISABLE
77+
PR_SPEC_DISABLE nor PR_SPEC_FORCE_DISABLE
7478

7579
ENXIO Control of the selected speculation misfeature is not possible.
7680
See PR_GET_SPECULATION_CTRL.
81+
82+
EPERM Speculation was disabled with PR_SPEC_FORCE_DISABLE and caller
83+
tried to enable it again.
7784
======= =================================================================
7885

7986
Speculation misfeature controls
@@ -84,3 +91,4 @@ Speculation misfeature controls
8491
* prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0);
8592
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0);
8693
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0);
94+
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0);

arch/x86/kernel/cpu/bugs.c

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -814,21 +814,37 @@ static void ssb_select_mitigation()
814814

815815
static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
816816
{
817-
bool rds = !!test_tsk_thread_flag(task, TIF_RDS);
817+
bool update;
818818

819819
if (ssb_mode != SPEC_STORE_BYPASS_PRCTL)
820820
return -ENXIO;
821821

822-
if (ctrl == PR_SPEC_ENABLE)
823-
clear_tsk_thread_flag(task, TIF_RDS);
824-
else
825-
set_tsk_thread_flag(task, TIF_RDS);
822+
switch (ctrl) {
823+
case PR_SPEC_ENABLE:
824+
/* If speculation is force disabled, enable is not allowed */
825+
if (task_spec_ssb_force_disable(task))
826+
return -EPERM;
827+
task_clear_spec_ssb_disable(task);
828+
update = test_and_clear_tsk_thread_flag(task, TIF_RDS);
829+
break;
830+
case PR_SPEC_DISABLE:
831+
task_set_spec_ssb_disable(task);
832+
update = !test_and_set_tsk_thread_flag(task, TIF_RDS);
833+
break;
834+
case PR_SPEC_FORCE_DISABLE:
835+
task_set_spec_ssb_disable(task);
836+
task_set_spec_ssb_force_disable(task);
837+
update = !test_and_set_tsk_thread_flag(task, TIF_RDS);
838+
break;
839+
default:
840+
return -ERANGE;
841+
}
826842

827843
/*
828844
* If being set on non-current task, delay setting the CPU
829845
* mitigation until it is next scheduled.
830846
*/
831-
if (task == current && rds != !!test_tsk_thread_flag(task, TIF_RDS))
847+
if (task == current && update)
832848
speculative_store_bypass_update();
833849

834850
return 0;
@@ -841,7 +857,9 @@ static int ssb_prctl_get(struct task_struct *task)
841857
case SPEC_STORE_BYPASS_DISABLE:
842858
return PR_SPEC_DISABLE;
843859
case SPEC_STORE_BYPASS_PRCTL:
844-
if (test_tsk_thread_flag(task, TIF_RDS))
860+
if (task_spec_ssb_force_disable(task))
861+
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
862+
if (task_spec_ssb_disable(task))
845863
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
846864
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
847865
default:
@@ -854,9 +872,6 @@ static int ssb_prctl_get(struct task_struct *task)
854872
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
855873
unsigned long ctrl)
856874
{
857-
if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE)
858-
return -ERANGE;
859-
860875
switch (which) {
861876
case PR_SPEC_STORE_BYPASS:
862877
return ssb_prctl_set(task, ctrl);

fs/proc/array.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
356356
case PR_SPEC_NOT_AFFECTED:
357357
seq_printf(m, "not vulnerable");
358358
break;
359+
case PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE:
360+
seq_printf(m, "thread force mitigated");
361+
break;
359362
case PR_SPEC_PRCTL | PR_SPEC_DISABLE:
360363
seq_printf(m, "thread mitigated");
361364
break;

include/linux/sched.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1389,7 +1389,8 @@ static inline bool is_percpu_thread(void)
13891389
#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */
13901390
#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */
13911391
#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */
1392-
1392+
#define PFA_SPEC_SSB_DISABLE 3 /* Speculative Store Bypass disabled */
1393+
#define PFA_SPEC_SSB_FORCE_DISABLE 4 /* Speculative Store Bypass force disabled*/
13931394

13941395
#define TASK_PFA_TEST(name, func) \
13951396
static inline bool task_##func(struct task_struct *p) \
@@ -1414,6 +1415,13 @@ TASK_PFA_TEST(SPREAD_SLAB, spread_slab)
14141415
TASK_PFA_SET(SPREAD_SLAB, spread_slab)
14151416
TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab)
14161417

1418+
TASK_PFA_TEST(SPEC_SSB_DISABLE, spec_ssb_disable)
1419+
TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable)
1420+
TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable)
1421+
1422+
TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
1423+
TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
1424+
14171425
static inline void
14181426
current_restore_flags(unsigned long orig_flags, unsigned long flags)
14191427
{

include/uapi/linux/prctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,5 +217,6 @@ struct prctl_mm_map {
217217
# define PR_SPEC_PRCTL (1UL << 0)
218218
# define PR_SPEC_ENABLE (1UL << 1)
219219
# define PR_SPEC_DISABLE (1UL << 2)
220+
# define PR_SPEC_FORCE_DISABLE (1UL << 3)
220221

221222
#endif /* _LINUX_PRCTL_H */

0 commit comments

Comments
 (0)