Skip to content

Commit 9137bb2

Browse files
committed
x86/speculation: Add prctl() control for indirect branch speculation
Add the PR_SPEC_INDIRECT_BRANCH option for the PR_GET_SPECULATION_CTRL and PR_SET_SPECULATION_CTRL prctls to allow fine grained per task control of indirect branch speculation via STIBP and IBPB. Invocations: Check indirect branch speculation status with - prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, 0, 0, 0); Enable indirect branch speculation with - prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_ENABLE, 0, 0); Disable indirect branch speculation with - prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_DISABLE, 0, 0); Force disable indirect branch speculation with - prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0); See Documentation/userspace-api/spec_ctrl.rst. Signed-off-by: Tim Chen <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Jiri Kosina <[email protected]> Cc: Tom Lendacky <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: David Woodhouse <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Casey Schaufler <[email protected]> Cc: Asit Mallick <[email protected]> Cc: Arjan van de Ven <[email protected]> Cc: Jon Masters <[email protected]> Cc: Waiman Long <[email protected]> Cc: Greg KH <[email protected]> Cc: Dave Stewart <[email protected]> Cc: Kees Cook <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent 6893a95 commit 9137bb2

File tree

7 files changed

+93
-0
lines changed

7 files changed

+93
-0
lines changed

Documentation/userspace-api/spec_ctrl.rst

+9
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,12 @@ Speculation misfeature controls
9292
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0);
9393
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0);
9494
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0);
95+
96+
- PR_SPEC_INDIR_BRANCH: Indirect Branch Speculation in User Processes
97+
(Mitigate Spectre V2 style attacks against user processes)
98+
99+
Invocations:
100+
* prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, 0, 0, 0);
101+
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_ENABLE, 0, 0);
102+
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_DISABLE, 0, 0);
103+
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0);

arch/x86/include/asm/nospec-branch.h

+1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ enum spectre_v2_mitigation {
232232
enum spectre_v2_user_mitigation {
233233
SPECTRE_V2_USER_NONE,
234234
SPECTRE_V2_USER_STRICT,
235+
SPECTRE_V2_USER_PRCTL,
235236
};
236237

237238
/* The Speculative Store Bypass disable variants */

arch/x86/kernel/cpu/bugs.c

+67
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,8 @@ void arch_smt_update(void)
566566
case SPECTRE_V2_USER_STRICT:
567567
update_stibp_strict();
568568
break;
569+
case SPECTRE_V2_USER_PRCTL:
570+
break;
569571
}
570572

571573
mutex_unlock(&spec_ctrl_mutex);
@@ -752,12 +754,50 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
752754
return 0;
753755
}
754756

757+
static int ib_prctl_set(struct task_struct *task, unsigned long ctrl)
758+
{
759+
switch (ctrl) {
760+
case PR_SPEC_ENABLE:
761+
if (spectre_v2_user == SPECTRE_V2_USER_NONE)
762+
return 0;
763+
/*
764+
* Indirect branch speculation is always disabled in strict
765+
* mode.
766+
*/
767+
if (spectre_v2_user == SPECTRE_V2_USER_STRICT)
768+
return -EPERM;
769+
task_clear_spec_ib_disable(task);
770+
task_update_spec_tif(task);
771+
break;
772+
case PR_SPEC_DISABLE:
773+
case PR_SPEC_FORCE_DISABLE:
774+
/*
775+
* Indirect branch speculation is always allowed when
776+
* mitigation is force disabled.
777+
*/
778+
if (spectre_v2_user == SPECTRE_V2_USER_NONE)
779+
return -EPERM;
780+
if (spectre_v2_user == SPECTRE_V2_USER_STRICT)
781+
return 0;
782+
task_set_spec_ib_disable(task);
783+
if (ctrl == PR_SPEC_FORCE_DISABLE)
784+
task_set_spec_ib_force_disable(task);
785+
task_update_spec_tif(task);
786+
break;
787+
default:
788+
return -ERANGE;
789+
}
790+
return 0;
791+
}
792+
755793
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
756794
unsigned long ctrl)
757795
{
758796
switch (which) {
759797
case PR_SPEC_STORE_BYPASS:
760798
return ssb_prctl_set(task, ctrl);
799+
case PR_SPEC_INDIRECT_BRANCH:
800+
return ib_prctl_set(task, ctrl);
761801
default:
762802
return -ENODEV;
763803
}
@@ -790,11 +830,34 @@ static int ssb_prctl_get(struct task_struct *task)
790830
}
791831
}
792832

833+
static int ib_prctl_get(struct task_struct *task)
834+
{
835+
if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
836+
return PR_SPEC_NOT_AFFECTED;
837+
838+
switch (spectre_v2_user) {
839+
case SPECTRE_V2_USER_NONE:
840+
return PR_SPEC_ENABLE;
841+
case SPECTRE_V2_USER_PRCTL:
842+
if (task_spec_ib_force_disable(task))
843+
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
844+
if (task_spec_ib_disable(task))
845+
return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
846+
return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
847+
case SPECTRE_V2_USER_STRICT:
848+
return PR_SPEC_DISABLE;
849+
default:
850+
return PR_SPEC_NOT_AFFECTED;
851+
}
852+
}
853+
793854
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
794855
{
795856
switch (which) {
796857
case PR_SPEC_STORE_BYPASS:
797858
return ssb_prctl_get(task);
859+
case PR_SPEC_INDIRECT_BRANCH:
860+
return ib_prctl_get(task);
798861
default:
799862
return -ENODEV;
800863
}
@@ -974,6 +1037,8 @@ static char *stibp_state(void)
9741037
return ", STIBP: disabled";
9751038
case SPECTRE_V2_USER_STRICT:
9761039
return ", STIBP: forced";
1040+
case SPECTRE_V2_USER_PRCTL:
1041+
return "";
9771042
}
9781043
return "";
9791044
}
@@ -986,6 +1051,8 @@ static char *ibpb_state(void)
9861051
return ", IBPB: disabled";
9871052
case SPECTRE_V2_USER_STRICT:
9881053
return ", IBPB: always-on";
1054+
case SPECTRE_V2_USER_PRCTL:
1055+
return "";
9891056
}
9901057
}
9911058
return "";

arch/x86/kernel/process.c

+5
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,11 @@ static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
450450
set_tsk_thread_flag(tsk, TIF_SSBD);
451451
else
452452
clear_tsk_thread_flag(tsk, TIF_SSBD);
453+
454+
if (task_spec_ib_disable(tsk))
455+
set_tsk_thread_flag(tsk, TIF_SPEC_IB);
456+
else
457+
clear_tsk_thread_flag(tsk, TIF_SPEC_IB);
453458
}
454459
/* Return the updated threadinfo flags*/
455460
return task_thread_info(tsk)->flags;

include/linux/sched.h

+9
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,8 @@ static inline bool is_percpu_thread(void)
14531453
#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */
14541454
#define PFA_SPEC_SSB_DISABLE 3 /* Speculative Store Bypass disabled */
14551455
#define PFA_SPEC_SSB_FORCE_DISABLE 4 /* Speculative Store Bypass force disabled*/
1456+
#define PFA_SPEC_IB_DISABLE 5 /* Indirect branch speculation restricted */
1457+
#define PFA_SPEC_IB_FORCE_DISABLE 6 /* Indirect branch speculation permanently restricted */
14561458

14571459
#define TASK_PFA_TEST(name, func) \
14581460
static inline bool task_##func(struct task_struct *p) \
@@ -1484,6 +1486,13 @@ TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable)
14841486
TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
14851487
TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
14861488

1489+
TASK_PFA_TEST(SPEC_IB_DISABLE, spec_ib_disable)
1490+
TASK_PFA_SET(SPEC_IB_DISABLE, spec_ib_disable)
1491+
TASK_PFA_CLEAR(SPEC_IB_DISABLE, spec_ib_disable)
1492+
1493+
TASK_PFA_TEST(SPEC_IB_FORCE_DISABLE, spec_ib_force_disable)
1494+
TASK_PFA_SET(SPEC_IB_FORCE_DISABLE, spec_ib_force_disable)
1495+
14871496
static inline void
14881497
current_restore_flags(unsigned long orig_flags, unsigned long flags)
14891498
{

include/uapi/linux/prctl.h

+1
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ struct prctl_mm_map {
212212
#define PR_SET_SPECULATION_CTRL 53
213213
/* Speculation control variants */
214214
# define PR_SPEC_STORE_BYPASS 0
215+
# define PR_SPEC_INDIRECT_BRANCH 1
215216
/* Return and control values for PR_SET/GET_SPECULATION_CTRL */
216217
# define PR_SPEC_NOT_AFFECTED 0
217218
# define PR_SPEC_PRCTL (1UL << 0)

tools/include/uapi/linux/prctl.h

+1
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ struct prctl_mm_map {
212212
#define PR_SET_SPECULATION_CTRL 53
213213
/* Speculation control variants */
214214
# define PR_SPEC_STORE_BYPASS 0
215+
# define PR_SPEC_INDIRECT_BRANCH 1
215216
/* Return and control values for PR_SET/GET_SPECULATION_CTRL */
216217
# define PR_SPEC_NOT_AFFECTED 0
217218
# define PR_SPEC_PRCTL (1UL << 0)

0 commit comments

Comments
 (0)