diff options
author | Kees Cook <keescook@chromium.org> | 2018-05-03 17:56:12 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-05-04 18:51:44 -0400 |
commit | 00a02d0c502a06d15e07b857f8ff921e3e402675 (patch) | |
tree | d1f2bd8ff6733e43840a199d11e455790d7c21c8 | |
parent | b849a812f7eb92e96d1c8239b06581b2cfd8b275 (diff) |
seccomp: Add filter flag to opt-out of SSB mitigation
If 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.
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/seccomp.h | 5 | ||||
-rw-r--r-- | include/uapi/linux/seccomp.h | 5 | ||||
-rw-r--r-- | kernel/seccomp.c | 19 | ||||
-rw-r--r-- | tools/testing/selftests/seccomp/seccomp_bpf.c | 22 |
4 files changed, 36 insertions, 15 deletions
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index c723a5c4e3ff..e5320f6c8654 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
@@ -4,8 +4,9 @@ | |||
4 | 4 | ||
5 | #include <uapi/linux/seccomp.h> | 5 | #include <uapi/linux/seccomp.h> |
6 | 6 | ||
7 | #define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ | 7 | #define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \ |
8 | SECCOMP_FILTER_FLAG_LOG) | 8 | SECCOMP_FILTER_FLAG_LOG | \ |
9 | SECCOMP_FILTER_FLAG_SPEC_ALLOW) | ||
9 | 10 | ||
10 | #ifdef CONFIG_SECCOMP | 11 | #ifdef CONFIG_SECCOMP |
11 | 12 | ||
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index 2a0bd9dd104d..9efc0e73d50b 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h | |||
@@ -17,8 +17,9 @@ | |||
17 | #define SECCOMP_GET_ACTION_AVAIL 2 | 17 | #define SECCOMP_GET_ACTION_AVAIL 2 |
18 | 18 | ||
19 | /* Valid flags for SECCOMP_SET_MODE_FILTER */ | 19 | /* Valid flags for SECCOMP_SET_MODE_FILTER */ |
20 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | 20 | #define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) |
21 | #define SECCOMP_FILTER_FLAG_LOG 2 | 21 | #define SECCOMP_FILTER_FLAG_LOG (1UL << 1) |
22 | #define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * All BPF programs must return a 32-bit value. | 25 | * All BPF programs must return a 32-bit value. |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 2c819d65e15f..53eb946120c1 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -243,7 +243,8 @@ static inline void spec_mitigate(struct task_struct *task, | |||
243 | } | 243 | } |
244 | 244 | ||
245 | static inline void seccomp_assign_mode(struct task_struct *task, | 245 | static inline void seccomp_assign_mode(struct task_struct *task, |
246 | unsigned long seccomp_mode) | 246 | unsigned long seccomp_mode, |
247 | unsigned long flags) | ||
247 | { | 248 | { |
248 | assert_spin_locked(&task->sighand->siglock); | 249 | assert_spin_locked(&task->sighand->siglock); |
249 | 250 | ||
@@ -253,8 +254,9 @@ static inline void seccomp_assign_mode(struct task_struct *task, | |||
253 | * filter) is set. | 254 | * filter) is set. |
254 | */ | 255 | */ |
255 | smp_mb__before_atomic(); | 256 | smp_mb__before_atomic(); |
256 | /* Assume seccomp processes want speculation flaw mitigation. */ | 257 | /* Assume default seccomp processes want spec flaw mitigation. */ |
257 | spec_mitigate(task, PR_SPEC_STORE_BYPASS); | 258 | if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0) |
259 | spec_mitigate(task, PR_SPEC_STORE_BYPASS); | ||
258 | set_tsk_thread_flag(task, TIF_SECCOMP); | 260 | set_tsk_thread_flag(task, TIF_SECCOMP); |
259 | } | 261 | } |
260 | 262 | ||
@@ -322,7 +324,7 @@ static inline pid_t seccomp_can_sync_threads(void) | |||
322 | * without dropping the locks. | 324 | * without dropping the locks. |
323 | * | 325 | * |
324 | */ | 326 | */ |
325 | static inline void seccomp_sync_threads(void) | 327 | static inline void seccomp_sync_threads(unsigned long flags) |
326 | { | 328 | { |
327 | struct task_struct *thread, *caller; | 329 | struct task_struct *thread, *caller; |
328 | 330 | ||
@@ -363,7 +365,8 @@ static inline void seccomp_sync_threads(void) | |||
363 | * allow one thread to transition the other. | 365 | * allow one thread to transition the other. |
364 | */ | 366 | */ |
365 | if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) | 367 | if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) |
366 | seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); | 368 | seccomp_assign_mode(thread, SECCOMP_MODE_FILTER, |
369 | flags); | ||
367 | } | 370 | } |
368 | } | 371 | } |
369 | 372 | ||
@@ -486,7 +489,7 @@ static long seccomp_attach_filter(unsigned int flags, | |||
486 | 489 | ||
487 | /* Now that the new filter is in place, synchronize to all threads. */ | 490 | /* Now that the new filter is in place, synchronize to all threads. */ |
488 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) | 491 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) |
489 | seccomp_sync_threads(); | 492 | seccomp_sync_threads(flags); |
490 | 493 | ||
491 | return 0; | 494 | return 0; |
492 | } | 495 | } |
@@ -835,7 +838,7 @@ static long seccomp_set_mode_strict(void) | |||
835 | #ifdef TIF_NOTSC | 838 | #ifdef TIF_NOTSC |
836 | disable_TSC(); | 839 | disable_TSC(); |
837 | #endif | 840 | #endif |
838 | seccomp_assign_mode(current, seccomp_mode); | 841 | seccomp_assign_mode(current, seccomp_mode, 0); |
839 | ret = 0; | 842 | ret = 0; |
840 | 843 | ||
841 | out: | 844 | out: |
@@ -893,7 +896,7 @@ static long seccomp_set_mode_filter(unsigned int flags, | |||
893 | /* Do not free the successfully attached filter. */ | 896 | /* Do not free the successfully attached filter. */ |
894 | prepared = NULL; | 897 | prepared = NULL; |
895 | 898 | ||
896 | seccomp_assign_mode(current, seccomp_mode); | 899 | seccomp_assign_mode(current, seccomp_mode, flags); |
897 | out: | 900 | out: |
898 | spin_unlock_irq(¤t->sighand->siglock); | 901 | spin_unlock_irq(¤t->sighand->siglock); |
899 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) | 902 | if (flags & SECCOMP_FILTER_FLAG_TSYNC) |
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 168c66d74fc5..e1473234968d 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c | |||
@@ -134,11 +134,15 @@ struct seccomp_data { | |||
134 | #endif | 134 | #endif |
135 | 135 | ||
136 | #ifndef SECCOMP_FILTER_FLAG_TSYNC | 136 | #ifndef SECCOMP_FILTER_FLAG_TSYNC |
137 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | 137 | #define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) |
138 | #endif | 138 | #endif |
139 | 139 | ||
140 | #ifndef SECCOMP_FILTER_FLAG_LOG | 140 | #ifndef SECCOMP_FILTER_FLAG_LOG |
141 | #define SECCOMP_FILTER_FLAG_LOG 2 | 141 | #define SECCOMP_FILTER_FLAG_LOG (1UL << 1) |
142 | #endif | ||
143 | |||
144 | #ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW | ||
145 | #define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) | ||
142 | #endif | 146 | #endif |
143 | 147 | ||
144 | #ifndef PTRACE_SECCOMP_GET_METADATA | 148 | #ifndef PTRACE_SECCOMP_GET_METADATA |
@@ -2072,14 +2076,26 @@ TEST(seccomp_syscall_mode_lock) | |||
2072 | TEST(detect_seccomp_filter_flags) | 2076 | TEST(detect_seccomp_filter_flags) |
2073 | { | 2077 | { |
2074 | unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC, | 2078 | unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC, |
2075 | SECCOMP_FILTER_FLAG_LOG }; | 2079 | SECCOMP_FILTER_FLAG_LOG, |
2080 | SECCOMP_FILTER_FLAG_SPEC_ALLOW }; | ||
2076 | unsigned int flag, all_flags; | 2081 | unsigned int flag, all_flags; |
2077 | int i; | 2082 | int i; |
2078 | long ret; | 2083 | long ret; |
2079 | 2084 | ||
2080 | /* Test detection of known-good filter flags */ | 2085 | /* Test detection of known-good filter flags */ |
2081 | for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) { | 2086 | for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) { |
2087 | int bits = 0; | ||
2088 | |||
2082 | flag = flags[i]; | 2089 | flag = flags[i]; |
2090 | /* Make sure the flag is a single bit! */ | ||
2091 | while (flag) { | ||
2092 | if (flag & 0x1) | ||
2093 | bits ++; | ||
2094 | flag >>= 1; | ||
2095 | } | ||
2096 | ASSERT_EQ(1, bits); | ||
2097 | flag = flags[i]; | ||
2098 | |||
2083 | ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); | 2099 | ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); |
2084 | ASSERT_NE(ENOSYS, errno) { | 2100 | ASSERT_NE(ENOSYS, errno) { |
2085 | TH_LOG("Kernel does not support seccomp syscall!"); | 2101 | TH_LOG("Kernel does not support seccomp syscall!"); |