seccomp use-after-free fix
- Add logic for making some seccomp flags exclusive (Tycho) - Update selftests for exclusivity testing (Kees) -----BEGIN PGP SIGNATURE----- Comment: Kees Cook <kees@outflux.net> iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAlzHVl0WHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJqZuD/wK/PccncrPcBVtyFwWVVPj1HaM 97icUgcbzC2mgpGmIDj5lZwpzXjvSlvkLenwcX+QEO0BfRbomUtcFqiMo3GMsHE3 JMJDQ4r+eQLZX2r/f0rgJ+yS80DzpgF4PjLbC2kcDXdVTNUBetafwq4tfP1wEYbE Fumw64hjJidvahKUlJh94xQzatBFSA6gzPcWCn6VbFKDIQ/Zu1zMvWPxsVqOEAol rNSW5qFlxHI35znMg2/5tfZ8Z9bbemYcYDwlWwCZkNcoRBfs5rpgFhYuE5o5qYZT ndQQnfv24HoH0Q1zMq67uLdcPwVzg8VQjKQiZr9QWhKfSsFi8mtd00/yvqm9z/Hy 1gwHv6bSzmfNyPYoFCTHKrMutUKy9aUHBdPjXdjOOD6V30QWbCETUHQ+Ipkq7qCm YbIhJL/FRHF2BAFU7uT+2/xob9JGD80n5nYZtZDdBx0zgDZb5xTuSN8fi8jVf+Ye so6Zwu64OdcAt+AGIl0Q3f+bCBYnjLF1Ec14TfJgOZAuw1fdsi8uAsFBV+aHu7tP SsDqDLCcY6p98x7AlFpEf4pN4oIC7kWOMFdJH7dK9pNeh4Q6Omf0vpHY6tAxC8yX LsFcimfKgJnlGPoqLN04Aq3K5Qj55lcpNv8RbQ5YuKujzhHH3/yltNCWSR59TFsz anZKkfzZckEdoJ9vSg== =12Pp -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
83a50840e7
@ -502,7 +502,10 @@ out:
|
||||
*
|
||||
* 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,
|
||||
struct seccomp_filter *filter)
|
||||
@ -1258,6 +1261,16 @@ static long seccomp_set_mode_filter(unsigned int flags,
|
||||
if (flags & ~SECCOMP_FILTER_FLAG_MASK)
|
||||
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. */
|
||||
prepared = seccomp_prepare_user_filter(filter);
|
||||
if (IS_ERR(prepared))
|
||||
@ -1304,7 +1317,7 @@ out:
|
||||
mutex_unlock(¤t->signal->cred_guard_mutex);
|
||||
out_put_fd:
|
||||
if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) {
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
listener_f->private_data = NULL;
|
||||
fput(listener_f);
|
||||
put_unused_fd(listener);
|
||||
|
@ -2166,11 +2166,14 @@ TEST(detect_seccomp_filter_flags)
|
||||
SECCOMP_FILTER_FLAG_LOG,
|
||||
SECCOMP_FILTER_FLAG_SPEC_ALLOW,
|
||||
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;
|
||||
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++) {
|
||||
int bits = 0;
|
||||
|
||||
@ -2197,16 +2200,29 @@ TEST(detect_seccomp_filter_flags)
|
||||
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 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(EFAULT, errno) {
|
||||
TH_LOG("Failed to detect that all known-good filter flags (0x%X) are supported!",
|
||||
flag);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test detection of an unknown filter flag */
|
||||
/* Test detection of an unknown filter flags, without exclusives. */
|
||||
flag = -1;
|
||||
flag &= ~exclusive_mask;
|
||||
ret = seccomp(SECCOMP_SET_MODE_FILTER, flag, NULL);
|
||||
EXPECT_EQ(-1, ret);
|
||||
EXPECT_EQ(EINVAL, errno) {
|
||||
|
Loading…
Reference in New Issue
Block a user