diff options
author | Tycho Andersen <tycho@tycho.ws> | 2019-01-12 11:24:20 -0700 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2019-01-15 09:43:12 -0800 |
commit | a811dc61559e0c8003f1086c2a4dc8e4d5ae4cb8 (patch) | |
tree | 56144b909f723d0bf4365c2ccbd8ec2e24d9907d | |
parent | 7939f8beecf1cfb10d255be65bfbd3793fae82a1 (diff) | |
download | linux-a811dc61559e0c8003f1086c2a4dc8e4d5ae4cb8.tar.bz2 |
seccomp: fix UAF in user-trap code
On the failure path, we do an fput() of the listener fd if the filter fails
to install (e.g. because of a TSYNC race that's lost, or if the thread is
killed, etc.). fput() doesn't actually release the fd, it just ads it to a
work queue. Then the thread proceeds to free the filter, even though the
listener struct file has a reference to it.
To fix this, on the failure path let's set the private data to null, so we
know in ->release() to ignore the filter.
Reported-by: syzbot+981c26489b2d1c6316ba@syzkaller.appspotmail.com
Fixes: 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace")
Signed-off-by: Tycho Andersen <tycho@tycho.ws>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: James Morris <james.morris@microsoft.com>
-rw-r--r-- | kernel/seccomp.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index d7f538847b84..e815781ed751 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -976,6 +976,9 @@ static int seccomp_notify_release(struct inode *inode, struct file *file) struct seccomp_filter *filter = file->private_data; struct seccomp_knotif *knotif; + if (!filter) + return 0; + mutex_lock(&filter->notify_lock); /* @@ -1300,6 +1303,7 @@ out: out_put_fd: if (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) { if (ret < 0) { + listener_f->private_data = NULL; fput(listener_f); put_unused_fd(listener); } else { |