SSB update 0
Subsystems (7)
v2 cover SSB update 0
Changes since v1:
- Fix the fallout from the first version (Kees)
- Rework the state storage a bit in preparation for the dynamic BPF control
Delta patch below. Git bundle follows in separate mail.
Thanks,
tglx
8<--------------
arch/x86/kernel/cpu/bugs.c +16 -9
@@ -540,10 +540,11 @@ static void ssb_select_mitigation() }#undef pr_fmt +#define pr_fmt (fmt) "Speculation prctl: " fmtstatic 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 && ssb_mode !=SPEC_STORE_BYPASS_SECCOMP )
@@ -552,16 +553,19 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)switch (ctrl) {case PR_SPEC_ENABLE :/* If speculation is force disabled, enable is not allowed */ -if (task_spec_force_disable (task)) +if (task_spec_ssb_force_disable (task))return -EPERM ; -clear_tsk_thread_flag (task,TIF_RDS ); +task_clear_spec_ssb_disable (task); + update =test_and_clear_tsk_thread_flag (task,TIF_RDS );break ;case PR_SPEC_DISABLE : -set_tsk_thread_flag (task,TIF_RDS ); +task_set_spec_ssb_disable (task); + update = !test_and_set_tsk_thread_flag (task,TIF_RDS );break ;case PR_SPEC_FORCE_DISABLE : -set_tsk_thread_flag (task,TIF_RDS ); -task_set_spec_force_disable (task); +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 ;
@@ -571,7 +575,7 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)* 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 ;
@@ -588,21 +592,24 @@ int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, } } +#ifdef CONFIG_SECCOMP void arch_seccomp_spec_mitigate (struct task_struct *task) {if (ssb_mode ==SPEC_STORE_BYPASS_SECCOMP )ssb_prctl_set (task,PR_SPEC_FORCE_DISABLE ); } +#endif static int ssb_prctl_get (struct task_struct *task) {switch (ssb_mode) {case SPEC_STORE_BYPASS_DISABLE :return PR_SPEC_DISABLE ; +case SPEC_STORE_BYPASS_SECCOMP :case SPEC_STORE_BYPASS_PRCTL : -if (task_spec_force_disable (task)) +if (task_spec_ssb_force_disable (task))return PR_SPEC_PRCTL |PR_SPEC_FORCE_DISABLE ; -if (test_tsk_thread_flag (task,TIF_RDS )) +if (task_spec_ssb_disable (task))return PR_SPEC_PRCTL |PR_SPEC_DISABLE ;return PR_SPEC_PRCTL |PR_SPEC_ENABLE ;default :
include/linux/sched.h +8 -4
@@ -1393,8 +1393,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_FORCE_DISABLE 3/* Force disable speculation */ - +#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) \
@@ -1419,8 +1419,12 @@ 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_FORCE_DISABLE, spec_force_disable) -TASK_PFA_SET(SPEC_FORCE_DISABLE, spec_force_disable) +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)
include/linux/seccomp.h +3 -2
@@ -4,8 +4,9 @@#include <uapi/linux/seccomp.h> -#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ - SECCOMP_FILTER_FLAG_LOG) +#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ + SECCOMP_FILTER_FLAG_LOG | \ + SECCOMP_FILTER_FLAG_SPEC_ALLOW)#ifdef CONFIG_SECCOMP
include/uapi/linux/seccomp.h +3 -3
@@ -17,9 +17,9 @@#define SECCOMP_GET_ACTION_AVAIL 2/* Valid flags for SECCOMP_SET_MODE_FILTER */ -#define SECCOMP_FILTER_FLAG_TSYNC 1 -#define SECCOMP_FILTER_FLAG_LOG 2 -#define SECCOMP_FILTER_FLAG_SPEC_ALLOW 3 +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)/* * All BPF programs must return a 32-bit value.
tools/testing/selftests/seccomp/seccomp_bpf.c +14 -3
@@ -134,15 +134,15 @@ struct seccomp_data {#endif #ifndef SECCOMP_FILTER_FLAG_TSYNC -#define SECCOMP_FILTER_FLAG_TSYNC 1 +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)#endif #ifndef SECCOMP_FILTER_FLAG_LOG -#define SECCOMP_FILTER_FLAG_LOG 2 +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1)#endif #ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW -#define SECCOMP_FILTER_FLAG_SPEC_ALLOW 3 +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)#endif #ifndef PTRACE_SECCOMP_GET_METADATA
@@ -2084,7 +2084,18 @@ TEST(detect_seccomp_filter_flags)/* Test detection of known-good filter flags */ for (i =0 , all_flags =0 ; i <ARRAY_SIZE (flags); i++) { +int bits =0 ; + + flag = flags[i]; +/* Make sure the flag is a single bit! */ +while (flag) { +if (flag &0x1 ) + bits ++; + flag >>=1 ; + } +ASSERT_EQ (1 , bits); flag = flags[i]; + ret =seccomp (SECCOMP_SET_MODE_FILTER , flag,NULL ); ASSERT_NE(ENOSYS, errno) {TH_LOG ("Kernel does not support seccomp syscall!" );
PATCH v2 1/6 SSB update 1
There's no reason for these to be changed after boot.
--- arch/x86/kernel/cpu/bugs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/bugs.c +3 -2
@@ -129,7 +129,8 @@ static const char *spectre_v2_strings[]#undef pr_fmt#define pr_fmt (fmt) "Spectre V2 : " fmt -static enum spectre_v2_mitigation spectre_v2_enabled =SPECTRE_V2_NONE ; +static enum spectre_v2_mitigation spectre_v2_enabled__ro_after_init = +SPECTRE_V2_NONE ;void x86_spec_ctrl_set (u64 val) {
@@ -407,7 +408,7 @@ static void __init spectre_v2_select_mit#undef pr_fmt#define pr_fmt (fmt) "Speculative Store Bypass: " fmt -static enum ssb_mitigation ssb_mode =SPEC_STORE_BYPASS_NONE ; +static enum ssb_mitigation ssb_mode__ro_after_init =SPEC_STORE_BYPASS_NONE ;/* The kernel command line selection */ enum ssb_mitigation_cmd {
PATCH v2 2/6 SSB update 2
In reply to Thomas GleixnerFor 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.
--- Documentation/userspace-api/spec_ctrl.rst | 34 ++++++++++++++++++----------- arch/x86/kernel/cpu/bugs.c | 35 +++++++++++++++++++++--------- fs/proc/array.c | 3 ++ include/linux/sched.h | 10 +++++++- include/uapi/linux/prctl.h | 1 5 files changed, 59 insertions(+), 24 deletions(-)
Documentation/userspace-api/spec_ctrl.rst +21 -13
@@ -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.
@@ -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 ------------------
@@ -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
@@ -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);
arch/x86/kernel/cpu/bugs.c +25 -10
@@ -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 ;
@@ -559,7 +575,9 @@ static int ssb_prctl_get(struct task_strcase 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 :
@@ -572,9 +590,6 @@ static int ssb_prctl_get(struct task_strint 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);
fs/proc/array.c +3 -0
@@ -344,6 +344,9 @@ static inline void task_seccomp(struct scase 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 ;
include/linux/sched.h +9 -1
@@ -1393,7 +1393,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) \
@@ -1418,6 +1419,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) {
include/uapi/linux/prctl.h +1 -0
@@ -217,5 +217,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 */
PATCH v2 3/6 SSB update 3
In reply to Thomas GleixnerUse PR_SPEC_FORCE_DISABLE in seccomp() because seccomp does not allow to widen restrictions.
--- kernel/seccomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/seccomp.c +1 -1
@@ -239,7 +239,7 @@ static inline void spec_mitigate(structint state =arch_prctl_spec_ctrl_get (task, which);if (state >0 && (state &PR_SPEC_PRCTL )) -arch_prctl_spec_ctrl_set (task, which,PR_SPEC_DISABLE ); +arch_prctl_spec_ctrl_set (task, which,PR_SPEC_FORCE_DISABLE ); } static inline void seccomp_assign_mode(struct task_struct *task,
PATCH v2 4/6 SSB update 4
In reply to Thomas GleixnerIf a seccomp user is not interested in Speculative Store Bypass mitigation by default, it can set the new SECCOMP_FILTER_FLAG_SPEC_ALLOW flag when adding filters.
--- include/linux/seccomp.h | 5 +++-- include/uapi/linux/seccomp.h | 5 +++-- kernel/seccomp.c | 19 +++++++++++-------- tools/testing/selftests/seccomp/seccomp_bpf.c | 22 +++++++++++++++++++--- 4 files changed, 36 insertions(+), 15 deletions(-)
include/linux/seccomp.h +3 -2
@@ -4,8 +4,9 @@#include <uapi/linux/seccomp.h> -#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ - SECCOMP_FILTER_FLAG_LOG) +#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ + SECCOMP_FILTER_FLAG_LOG | \ + SECCOMP_FILTER_FLAG_SPEC_ALLOW)#ifdef CONFIG_SECCOMP
include/uapi/linux/seccomp.h +3 -2
@@ -17,8 +17,9 @@#define SECCOMP_GET_ACTION_AVAIL 2/* Valid flags for SECCOMP_SET_MODE_FILTER */ -#define SECCOMP_FILTER_FLAG_TSYNC 1 -#define SECCOMP_FILTER_FLAG_LOG 2 +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)/* * All BPF programs must return a 32-bit value.
kernel/seccomp.c +11 -8
@@ -243,7 +243,8 @@ static inline void spec_mitigate(struct }static inline void seccomp_assign_mode (struct task_struct *task, -unsigned long seccomp_mode) +unsigned long seccomp_mode, +unsigned long flags) {assert_spin_locked (&task->sighand->siglock);
@@ -253,8 +254,9 @@ static inline void seccomp_assign_mode(s* filter) is set. */ smp_mb__before_atomic (); -/* Assume seccomp processes want speculation flaw mitigation. */ -spec_mitigate (task,PR_SPEC_STORE_BYPASS ); +/* Assume default seccomp processes want spec flaw mitigation. */ +if ((flags &SECCOMP_FILTER_FLAG_SPEC_ALLOW ) ==0 ) +spec_mitigate (task,PR_SPEC_STORE_BYPASS );set_tsk_thread_flag (task,TIF_SECCOMP ); }
@@ -322,7 +324,7 @@ static inline pid_t seccomp_can_sync_thr* without dropping the locks. * */ -static inline void seccomp_sync_threads (void ) +static inline void seccomp_sync_threads (unsigned long flags) {struct task_struct *thread, *caller;
@@ -363,7 +365,8 @@ static inline void seccomp_sync_threads(* allow one thread to transition the other. */ if (thread->seccomp.mode ==SECCOMP_MODE_DISABLED ) -seccomp_assign_mode (thread,SECCOMP_MODE_FILTER ); +seccomp_assign_mode (thread,SECCOMP_MODE_FILTER , + flags); } }
@@ -486,7 +489,7 @@ static long seccomp_attach_filter(unsign/* Now that the new filter is in place, synchronize to all threads. */ if (flags &SECCOMP_FILTER_FLAG_TSYNC ) -seccomp_sync_threads (); +seccomp_sync_threads (flags);return 0 ; }
@@ -835,7 +838,7 @@ static long seccomp_set_mode_strict(void#ifdef TIF_NOTSC disable_TSC ();#endif -seccomp_assign_mode (current, seccomp_mode); +seccomp_assign_mode (current, seccomp_mode,0 ); ret =0 ; out:
@@ -893,7 +896,7 @@ static long seccomp_set_mode_filter(unsi/* Do not free the successfully attached filter. */ prepared =NULL ; -seccomp_assign_mode (current, seccomp_mode); +seccomp_assign_mode (current, seccomp_mode, flags); out:spin_unlock_irq (¤t->sighand->siglock);if (flags &SECCOMP_FILTER_FLAG_TSYNC )
tools/testing/selftests/seccomp/seccomp_bpf.c +19 -3
@@ -134,11 +134,15 @@ struct seccomp_data {#endif #ifndef SECCOMP_FILTER_FLAG_TSYNC -#define SECCOMP_FILTER_FLAG_TSYNC 1 +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)#endif #ifndef SECCOMP_FILTER_FLAG_LOG -#define SECCOMP_FILTER_FLAG_LOG 2 +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) +#endif + +#ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)#endif #ifndef PTRACE_SECCOMP_GET_METADATA
@@ -2072,14 +2076,26 @@ TEST(seccomp_syscall_mode_lock)TEST (detect_seccomp_filter_flags) {unsigned int flags[] = {SECCOMP_FILTER_FLAG_TSYNC , -SECCOMP_FILTER_FLAG_LOG }; +SECCOMP_FILTER_FLAG_LOG , +SECCOMP_FILTER_FLAG_SPEC_ALLOW };unsigned int flag, all_flags;int i;long ret;/* Test detection of known-good filter flags */ for (i =0 , all_flags =0 ; i <ARRAY_SIZE (flags); i++) { +int bits =0 ; + flag = flags[i]; +/* Make sure the flag is a single bit! */ +while (flag) { +if (flag &0x1 ) + bits ++; + flag >>=1 ; + } +ASSERT_EQ (1 , bits); + flag = flags[i]; + ret =seccomp (SECCOMP_SET_MODE_FILTER , flag,NULL ); ASSERT_NE(ENOSYS, errno) {TH_LOG ("Kernel does not support seccomp syscall!" );
PATCH v2 5/6 SSB update 5
In reply to Thomas GleixnerThe migitation control is simpler to implement in architecture code as it avoids the extra function call to check the mode. Aside of that having an explicit seccomp enabled mode in the architecture mitigations would require even more workarounds.
Move it into architecture code and provide a weak function in the seccomp code. Remove the 'which' argument as this allows the architecture to decide which mitigations are relevant for seccomp.
--- arch/x86/kernel/cpu/bugs.c | 29 ++++++++++++++++++----------- include/linux/nospec.h | 2 ++ kernel/seccomp.c | 15 ++------------- 3 files changed, 22 insertions(+), 24 deletions(-)
arch/x86/kernel/cpu/bugs.c +18 -11
@@ -569,6 +569,24 @@ static int ssb_prctl_set(struct task_strreturn 0 ; } +int arch_prctl_spec_ctrl_set (struct task_struct *task,unsigned long which, +unsigned long ctrl) +{ +switch (which) { +case PR_SPEC_STORE_BYPASS : +return ssb_prctl_set (task, ctrl); +default : +return -ENODEV ; + } +} + +#ifdef CONFIG_SECCOMP +void arch_seccomp_spec_mitigate (struct task_struct *task) +{ +ssb_prctl_set (task,PR_SPEC_FORCE_DISABLE ); +} +#endif +static int ssb_prctl_get (struct task_struct *task) {switch (ssb_mode) {
@@ -587,17 +605,6 @@ static int ssb_prctl_get(struct task_str } } -int arch_prctl_spec_ctrl_set (struct task_struct *task,unsigned long which, -unsigned long ctrl) -{ -switch (which) { -case PR_SPEC_STORE_BYPASS : -return ssb_prctl_set (task, ctrl); -default : -return -ENODEV ; - } -} -int arch_prctl_spec_ctrl_get (struct task_struct *task,unsigned long which) {switch (which) {
include/linux/nospec.h +2 -0
@@ -62,5 +62,7 @@ static inline unsigned long array_index_int arch_prctl_spec_ctrl_get (struct task_struct *task,unsigned long which);int arch_prctl_spec_ctrl_set (struct task_struct *task,unsigned long which,unsigned long ctrl); +/* Speculation control for seccomp enforced mitigation */ +void arch_seccomp_spec_mitigate (struct task_struct *task);#endif /* _LINUX_NOSPEC_H */
kernel/seccomp.c +2 -13
@@ -229,18 +229,7 @@ static inline bool seccomp_may_assign_moreturn true; } -/* -* If a given speculation mitigation is opt-in (prctl()-controlled), -* select it, by disabling speculation (enabling mitigation). -*/ -static inline void spec_mitigate (struct task_struct *task, -unsigned long which) -{ -int state =arch_prctl_spec_ctrl_get (task, which); - -if (state >0 && (state &PR_SPEC_PRCTL )) -arch_prctl_spec_ctrl_set (task, which,PR_SPEC_FORCE_DISABLE ); -} +void __weak arch_seccomp_spec_mitigate (struct task_struct *task) { } static inline void seccomp_assign_mode(struct task_struct *task, unsigned long seccomp_mode,
@@ -256,7 +245,7 @@ static inline void seccomp_assign_mode(ssmp_mb__before_atomic ();/* Assume default seccomp processes want spec flaw mitigation. */ if ((flags &SECCOMP_FILTER_FLAG_SPEC_ALLOW ) ==0 ) -spec_mitigate (task,PR_SPEC_STORE_BYPASS ); +arch_seccomp_spec_mitigate (task);set_tsk_thread_flag (task,TIF_SECCOMP ); }
PATCH v2 6/6 SSB update 6
In reply to Thomas GleixnerUnless explicitly opted out of, anything running under seccomp will have SSB mitigations enabled. Choosing the "prctl" mode will disable this.
[ tglx: Adjusted it to the new arch_seccomp_spec_mitigate() mechanism ]
--- Documentation/admin-guide/kernel-parameters.txt | 26 ++++++++++++------- arch/x86/include/asm/nospec-branch.h | 1 arch/x86/kernel/cpu/bugs.c | 32 +++++++++++++++++------- 3 files changed, 41 insertions(+), 18 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +17 -9
@@ -4049,19 +4049,27 @@ This parameter controls whether the Speculative Store Bypass optimization is used. - on - Unconditionally disable Speculative Store Bypass - off - Unconditionally enable Speculative Store Bypass - auto - Kernel detects whether the CPU model contains an - implementation of Speculative Store Bypass and - picks the most appropriate mitigation. - prctl - Control Speculative Store Bypass per thread - via prctl. Speculative Store Bypass is enabled - for a process by default. The state of the control - is inherited on fork. + on - Unconditionally disable Speculative Store Bypass + off - Unconditionally enable Speculative Store Bypass + auto - Kernel detects whether the CPU model contains an + implementation of Speculative Store Bypass and + picks the most appropriate mitigation. If the + CPU is not vulnerable, "off" is selected. If the + CPU is vulnerable the default mitigation is + architecture and Kconfig dependent. See below. + prctl - Control Speculative Store Bypass per thread + via prctl. Speculative Store Bypass is enabled + for a process by default. The state of the control + is inherited on fork. + seccomp - Same as "prctl" above, but all seccomp threads + will disable SSB unless they explicitly opt out. Not specifying this option is equivalent to spec_store_bypass_disable=auto. + Default mitigations: + X86: If CONFIG_SECCOMP=y "seccomp", otherwise "prctl" + spia_io_base= [HW,MTD] spia_fio_base= spia_pedr=
arch/x86/include/asm/nospec-branch.h +1 -0
@@ -233,6 +233,7 @@ enum ssb_mitigation {SPEC_STORE_BYPASS_NONE ,SPEC_STORE_BYPASS_DISABLE ,SPEC_STORE_BYPASS_PRCTL , + SPEC_STORE_BYPASS_SECCOMP, };extern char __indirect_thunk_start[];
arch/x86/kernel/cpu/bugs.c +23 -9
@@ -416,22 +416,25 @@ enum ssb_mitigation_cmd {SPEC_STORE_BYPASS_CMD_AUTO ,SPEC_STORE_BYPASS_CMD_ON ,SPEC_STORE_BYPASS_CMD_PRCTL , + SPEC_STORE_BYPASS_CMD_SECCOMP, };static const char *ssb_strings[] = { [SPEC_STORE_BYPASS_NONE ] ="Vulnerable" , [SPEC_STORE_BYPASS_DISABLE ] ="Mitigation: Speculative Store Bypass disabled" , - [SPEC_STORE_BYPASS_PRCTL ] ="Mitigation: Speculative Store Bypass disabled via prctl" + [SPEC_STORE_BYPASS_PRCTL ] ="Mitigation: Speculative Store Bypass disabled via prctl" , + [SPEC_STORE_BYPASS_SECCOMP ] ="Mitigation: Speculative Store Bypass disabled via prctl and seccomp" , };static const struct {const char *option;enum ssb_mitigation_cmd cmd; } ssb_mitigation_options[] = { - {"auto" ,SPEC_STORE_BYPASS_CMD_AUTO },/* Platform decides */ - {"on" ,SPEC_STORE_BYPASS_CMD_ON },/* Disable Speculative Store Bypass */ - {"off" ,SPEC_STORE_BYPASS_CMD_NONE },/* Don't touch Speculative Store Bypass */ - {"prctl" ,SPEC_STORE_BYPASS_CMD_PRCTL },/* Disable Speculative Store Bypass via prctl */ + {"auto" ,SPEC_STORE_BYPASS_CMD_AUTO },/* Platform decides */ + {"on" ,SPEC_STORE_BYPASS_CMD_ON },/* Disable Speculative Store Bypass */ + {"off" ,SPEC_STORE_BYPASS_CMD_NONE },/* Don't touch Speculative Store Bypass */ + {"prctl" ,SPEC_STORE_BYPASS_CMD_PRCTL },/* Disable Speculative Store Bypass via prctl */ + {"seccomp" ,SPEC_STORE_BYPASS_CMD_SECCOMP },/* Disable Speculative Store Bypass via prctl and seccomp */ };static enum ssb_mitigation_cmd __init ssb_parse_cmdline (void )
@@ -481,8 +484,15 @@ static enum ssb_mitigation_cmd __init __switch (cmd) {case SPEC_STORE_BYPASS_CMD_AUTO : -/* Choose prctl as the default mode */ - mode =SPEC_STORE_BYPASS_PRCTL ; +case SPEC_STORE_BYPASS_CMD_SECCOMP : +/* +* Choose prctl+seccomp as the default mode if seccomp is +* enabled. +*/ +if (IS_ENABLED (CONFIG_SECCOMP )) + mode =SPEC_STORE_BYPASS_SECCOMP ; +else + mode =SPEC_STORE_BYPASS_PRCTL ;break ;case SPEC_STORE_BYPASS_CMD_ON : mode =SPEC_STORE_BYPASS_DISABLE ;
@@ -530,12 +540,14 @@ static void ssb_select_mitigation() }#undef pr_fmt +#define pr_fmt (fmt) "Speculation prctl: " fmtstatic int ssb_prctl_set (struct task_struct *task,unsigned long ctrl) {bool update; -if (ssb_mode !=SPEC_STORE_BYPASS_PRCTL ) +if (ssb_mode !=SPEC_STORE_BYPASS_PRCTL && + ssb_mode !=SPEC_STORE_BYPASS_SECCOMP )return -ENXIO ;switch (ctrl) {
@@ -583,7 +595,8 @@ int arch_prctl_spec_ctrl_set(struct task#ifdef CONFIG_SECCOMP void arch_seccomp_spec_mitigate (struct task_struct *task) { -ssb_prctl_set (task,PR_SPEC_FORCE_DISABLE ); +if (ssb_mode ==SPEC_STORE_BYPASS_SECCOMP ) +ssb_prctl_set (task,PR_SPEC_FORCE_DISABLE ); }#endif
@@ -592,6 +605,7 @@ static int ssb_prctl_get(struct task_strswitch (ssb_mode) {case SPEC_STORE_BYPASS_DISABLE :return PR_SPEC_DISABLE ; +case SPEC_STORE_BYPASS_SECCOMP :case SPEC_STORE_BYPASS_PRCTL :if (task_spec_ssb_force_disable (task))return PR_SPEC_PRCTL |PR_SPEC_FORCE_DISABLE ;
Quoted 7 lines · speck for Thomas Gleixner
Changes since v1:
- Fix the fallout from the first version (Kees)
- Rework the state storage a bit in preparation for the dynamic BPF control
Delta patch below. Git bundle follows in separate mail.
Attached.
Thanks,
tglx