Commit 83a50840 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'seccomp-v5.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull seccomp fixes from Kees Cook:
 "Syzbot found a use-after-free bug in seccomp due to flags that should
  not be allowed to be used together.

  Tycho fixed this, I updated the self-tests, and the syzkaller PoC has
  been running for several days without triggering KASan (before this
  fix, it would reproduce). These patches have also been in -next for
  almost a week, just to be sure.

   - Add logic for making some seccomp flags exclusive (Tycho)

   - Update selftests for exclusivity testing (Kees)"

* tag 'seccomp-v5.1-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  seccomp: Make NEW_LISTENER and TSYNC flags exclusive
  selftests/seccomp: Prepare for exclusive seccomp flags
parents 80871482 7a0df7fb
...@@ -502,7 +502,10 @@ seccomp_prepare_user_filter(const char __user *user_filter) ...@@ -502,7 +502,10 @@ seccomp_prepare_user_filter(const char __user *user_filter)
* *
* Caller must be holding current->sighand->siglock lock. * Caller must be holding current->sighand->siglock lock.
* *
* Returns 0 on success, -ve on error. * Returns 0 on success, -ve on error, or
* - in TSYNC mode: the pid of a thread which was either not in the correct
* seccomp mode or did not have an ancestral seccomp filter
* - in NEW_LISTENER mode: the fd of the new listener
*/ */
static long seccomp_attach_filter(unsigned int flags, static long seccomp_attach_filter(unsigned int flags,
struct seccomp_filter *filter) struct seccomp_filter *filter)
...@@ -1258,6 +1261,16 @@ static long seccomp_set_mode_filter(unsigned int flags, ...@@ -1258,6 +1261,16 @@ static long seccomp_set_mode_filter(unsigned int flags,
if (flags & ~SECCOMP_FILTER_FLAG_MASK) if (flags & ~SECCOMP_FILTER_FLAG_MASK)
return -EINVAL; return -EINVAL;
/*
* In the successful case, NEW_LISTENER returns the new listener fd.
* But in the failure case, TSYNC returns the thread that died. If you
* combine these two flags, there's no way to tell whether something
* succeeded or failed. So, let's disallow this combination.
*/
if ((flags & SECCOMP_FILTER_FLAG_TSYNC) &&
(flags & SECCOMP_FILTER_FLAG_NEW_LISTENER))
return -EINVAL;
/* Prepare the new filter before holding any locks. */ /* Prepare the new filter before holding any locks. */
prepared = seccomp_prepare_user_filter(filter); prepared = seccomp_prepare_user_filter(filter);
if (IS_ERR(prepared)) if (IS_ERR(prepared))
...@@ -1304,7 +1317,7 @@ static long seccomp_set_mode_filter(unsigned int flags, ...@@ -1304,7 +1317,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
mutex_unlock(&current->signal->cred_guard_mutex); mutex_unlock(&current->signal->cred_guard_mutex);
out_put_fd: out_put_fd:
if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) { if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) {
if (ret < 0) { if (ret) {
listener_f->private_data = NULL; listener_f->private_data = NULL;
fput(listener_f); fput(listener_f);
put_unused_fd(listener); put_unused_fd(listener);
......
...@@ -2166,11 +2166,14 @@ TEST(detect_seccomp_filter_flags) ...@@ -2166,11 +2166,14 @@ TEST(detect_seccomp_filter_flags)
SECCOMP_FILTER_FLAG_LOG, SECCOMP_FILTER_FLAG_LOG,
SECCOMP_FILTER_FLAG_SPEC_ALLOW, SECCOMP_FILTER_FLAG_SPEC_ALLOW,
SECCOMP_FILTER_FLAG_NEW_LISTENER }; SECCOMP_FILTER_FLAG_NEW_LISTENER };
unsigned int flag, all_flags; unsigned int exclusive[] = {
SECCOMP_FILTER_FLAG_TSYNC,
SECCOMP_FILTER_FLAG_NEW_LISTENER };
unsigned int flag, all_flags, exclusive_mask;
int i; int i;
long ret; long ret;
/* Test detection of known-good filter flags */ /* Test detection of individual known-good filter flags */
for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) { for (i = 0, all_flags = 0; i < ARRAY_SIZE(flags); i++) {
int bits = 0; int bits = 0;
...@@ -2197,16 +2200,29 @@ TEST(detect_seccomp_filter_flags) ...@@ -2197,16 +2200,29 @@ TEST(detect_seccomp_filter_flags)
all_flags |= flag; all_flags |= flag;
} }
/* Test detection of all known-good filter flags */ /*
ret = seccomp(SECCOMP_SET_MODE_FILTER, all_flags, NULL); * Test detection of all known-good filter flags combined. But
* for the exclusive flags we need to mask them out and try them
* individually for the "all flags" testing.
*/
exclusive_mask = 0;
for (i = 0; i < ARRAY_SIZE(exclusive); i++)
exclusive_mask |= exclusive[i];
for (i = 0; i < ARRAY_SIZE(exclusive); i++) {
flag = all_flags & ~exclusive_mask;
flag |= exclusive[i];
ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
EXPECT_EQ(-1, ret); EXPECT_EQ(-1, ret);
EXPECT_EQ(EFAULT, errno) { EXPECT_EQ(EFAULT, errno) {
TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!", TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!",
all_flags); flag);
}
} }
/* Test detection of an unknown filter flag */ /* Test detection of an unknown filter flags, without exclusives. */
flag = -1; flag = -1;
flag &= ~exclusive_mask;
ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL); ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
EXPECT_EQ(-1, ret); EXPECT_EQ(-1, ret);
EXPECT_EQ(EINVAL, errno) { EXPECT_EQ(EINVAL, errno) {
......
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