seccomp: Add filter flag to opt-out of SSB mitigation
commit 00a02d0c502a06d15e07b857f8ff921e3e402675 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: Kees Cook <keescook@chromium.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c71def81cd
commit
ab677c2add
@ -3,7 +3,8 @@
|
||||
|
||||
#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
|
||||
|
||||
|
@ -15,7 +15,9 @@
|
||||
#define SECCOMP_SET_MODE_FILTER 1
|
||||
|
||||
/* 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.
|
||||
|
@ -230,7 +230,8 @@ static inline void spec_mitigate(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);
|
||||
|
||||
@ -240,8 +241,9 @@ static inline void seccomp_assign_mode(struct task_struct *task,
|
||||
* 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);
|
||||
}
|
||||
|
||||
@ -309,7 +311,7 @@ static inline pid_t seccomp_can_sync_threads(void)
|
||||
* 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;
|
||||
|
||||
@ -350,7 +352,8 @@ static inline void seccomp_sync_threads(void)
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,7 +472,7 @@ static long seccomp_attach_filter(unsigned int flags,
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@ -729,7 +732,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:
|
||||
@ -787,7 +790,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
|
||||
/* 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)
|
||||
|
@ -1692,7 +1692,11 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS)
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifndef seccomp
|
||||
@ -1791,6 +1795,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)
|
||||
{
|
||||
struct sock_filter filter[] = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user