Commit c463c0f0 authored by Kees Cook's avatar Kees Cook Committed by Greg Kroah-Hartman

seccomp: Add filter flag to opt-out of SSB mitigation

commit 00a02d0c upstream

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: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarDavid Woodhouse <dwmw@amazon.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarSrivatsa S. Bhat <srivatsa@csail.mit.edu>
Reviewed-by: default avatarMatt Helsley (VMware) <matt.helsley@gmail.com>
Reviewed-by: default avatarAlexey Makhalov <amakhalov@vmware.com>
Reviewed-by: default avatarBo Gan <ganb@vmware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a08c3f48
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
#include <uapi/linux/seccomp.h> #include <uapi/linux/seccomp.h>
#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC) #define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC | \
SECCOMP_FILTER_FLAG_SPEC_ALLOW)
#ifdef CONFIG_SECCOMP #ifdef CONFIG_SECCOMP
......
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#define SECCOMP_SET_MODE_FILTER 1 #define SECCOMP_SET_MODE_FILTER 1
/* Valid flags for SECCOMP_SET_MODE_FILTER */ /* Valid flags for SECCOMP_SET_MODE_FILTER */
#define SECCOMP_FILTER_FLAG_TSYNC 1 #define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
/* In v4.14+ SECCOMP_FILTER_FLAG_LOG is (1UL << 1) */
#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
/* /*
* All BPF programs must return a 32-bit value. * All BPF programs must return a 32-bit value.
......
...@@ -230,7 +230,8 @@ static inline void spec_mitigate(struct task_struct *task, ...@@ -230,7 +230,8 @@ static inline void spec_mitigate(struct task_struct *task,
} }
static inline void seccomp_assign_mode(struct task_struct *task, 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); assert_spin_locked(&task->sighand->siglock);
...@@ -240,8 +241,9 @@ static inline void seccomp_assign_mode(struct task_struct *task, ...@@ -240,8 +241,9 @@ static inline void seccomp_assign_mode(struct task_struct *task,
* filter) is set. * filter) is set.
*/ */
smp_mb__before_atomic(); smp_mb__before_atomic();
/* Assume seccomp processes want speculation flaw mitigation. */ /* Assume default seccomp processes want spec flaw mitigation. */
spec_mitigate(task, PR_SPEC_STORE_BYPASS); if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0)
spec_mitigate(task, PR_SPEC_STORE_BYPASS);
set_tsk_thread_flag(task, TIF_SECCOMP); set_tsk_thread_flag(task, TIF_SECCOMP);
} }
...@@ -309,7 +311,7 @@ static inline pid_t seccomp_can_sync_threads(void) ...@@ -309,7 +311,7 @@ static inline pid_t seccomp_can_sync_threads(void)
* without dropping the locks. * 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; struct task_struct *thread, *caller;
...@@ -350,7 +352,8 @@ static inline void seccomp_sync_threads(void) ...@@ -350,7 +352,8 @@ static inline void seccomp_sync_threads(void)
* allow one thread to transition the other. * allow one thread to transition the other.
*/ */
if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) if (thread->seccomp.mode == SECCOMP_MODE_DISABLED)
seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); seccomp_assign_mode(thread, SECCOMP_MODE_FILTER,
flags);
} }
} }
...@@ -469,7 +472,7 @@ static long seccomp_attach_filter(unsigned int flags, ...@@ -469,7 +472,7 @@ static long seccomp_attach_filter(unsigned int flags,
/* Now that the new filter is in place, synchronize to all threads. */ /* Now that the new filter is in place, synchronize to all threads. */
if (flags & SECCOMP_FILTER_FLAG_TSYNC) if (flags & SECCOMP_FILTER_FLAG_TSYNC)
seccomp_sync_threads(); seccomp_sync_threads(flags);
return 0; return 0;
} }
...@@ -764,7 +767,7 @@ static long seccomp_set_mode_strict(void) ...@@ -764,7 +767,7 @@ static long seccomp_set_mode_strict(void)
#ifdef TIF_NOTSC #ifdef TIF_NOTSC
disable_TSC(); disable_TSC();
#endif #endif
seccomp_assign_mode(current, seccomp_mode); seccomp_assign_mode(current, seccomp_mode, 0);
ret = 0; ret = 0;
out: out:
...@@ -822,7 +825,7 @@ static long seccomp_set_mode_filter(unsigned int flags, ...@@ -822,7 +825,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
/* Do not free the successfully attached filter. */ /* Do not free the successfully attached filter. */
prepared = NULL; prepared = NULL;
seccomp_assign_mode(current, seccomp_mode); seccomp_assign_mode(current, seccomp_mode, flags);
out: out:
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
if (flags & SECCOMP_FILTER_FLAG_TSYNC) if (flags & SECCOMP_FILTER_FLAG_TSYNC)
......
...@@ -1477,7 +1477,11 @@ TEST_F(TRACE_syscall, syscall_dropped) ...@@ -1477,7 +1477,11 @@ TEST_F(TRACE_syscall, syscall_dropped)
#endif #endif
#ifndef SECCOMP_FILTER_FLAG_TSYNC #ifndef SECCOMP_FILTER_FLAG_TSYNC
#define SECCOMP_FILTER_FLAG_TSYNC 1 #define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
#endif
#ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW
#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
#endif #endif
#ifndef seccomp #ifndef seccomp
...@@ -1576,6 +1580,78 @@ TEST(seccomp_syscall_mode_lock) ...@@ -1576,6 +1580,78 @@ TEST(seccomp_syscall_mode_lock)
} }
} }
/*
* Test detection of known and unknown filter flags. Userspace needs to be able
* to check if a filter flag is supported by the current kernel and a good way
* of doing that is by attempting to enter filter mode, with the flag bit in
* question set, and a NULL pointer for the _args_ parameter. EFAULT indicates
* that the flag is valid and EINVAL indicates that the flag is invalid.
*/
TEST(detect_seccomp_filter_flags)
{
unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC,
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!");
}
EXPECT_EQ(-1, ret);
EXPECT_EQ(EFAULT, errno) {
TH_LOG("Failed to detect that a known-good filter flag (0x%X) is supported!",
flag);
}
all_flags |= flag;
}
/* Test detection of all known-good filter flags */
ret = seccomp(SECCOMP_SET_MODE_FILTER, all_flags, NULL);
EXPECT_EQ(-1, ret);
EXPECT_EQ(EFAULT, errno) {
TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!",
all_flags);
}
/* Test detection of an unknown filter flag */
flag = -1;
ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
EXPECT_EQ(-1, ret);
EXPECT_EQ(EINVAL, errno) {
TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported!",
flag);
}
/*
* Test detection of an unknown filter flag that may simply need to be
* added to this test
*/
flag = flags[ARRAY_SIZE(flags) - 1] << 1;
ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
EXPECT_EQ(-1, ret);
EXPECT_EQ(EINVAL, errno) {
TH_LOG("Failed to detect that an unknown filter flag (0x%X) is unsupported! Does a new flag need to be added to this test?",
flag);
}
}
TEST(TSYNC_first) TEST(TSYNC_first)
{ {
struct sock_filter filter[] = { struct sock_filter filter[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment