mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-17 10:26:09 +00:00
seccomp: don't leak memory when filter install races
In seccomp_set_mode_filter() with TSYNC | NEW_LISTENER, we first initialize the listener fd, then check to see if we can actually use it later in seccomp_may_assign_mode(), which can fail if anyone else in our thread group has installed a filter and caused some divergence. If we can't, we partially clean up the newly allocated file: we put the fd, put the file, but don't actually clean up the *memory* that was allocated at filter->notif. Let's clean that up too. To accomplish this, let's hoist the actual "detach a notifier from a filter" code to its own helper out of seccomp_notify_release(), so that in case anyone adds stuff to init_listener(), they only have to add the cleanup code in one spot. This does a bit of extra locking and such on the failure path when the filter is not attached, but it's a slow failure path anyway. Fixes: 51891498f2da ("seccomp: allow TSYNC and USER_NOTIF together") Reported-by: syzbot+3ad9614a12f80994c32e@syzkaller.appspotmail.com Signed-off-by: Tycho Andersen <tycho@tycho.pizza> Acked-by: Christian Brauner <christian.brauner@ubuntu.com> Link: https://lore.kernel.org/r/20200902014017.934315-1-tycho@tycho.pizza Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
d012a7190f
commit
a566a9012a
@ -1109,13 +1109,12 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SECCOMP_FILTER
|
#ifdef CONFIG_SECCOMP_FILTER
|
||||||
static int seccomp_notify_release(struct inode *inode, struct file *file)
|
static void seccomp_notify_detach(struct seccomp_filter *filter)
|
||||||
{
|
{
|
||||||
struct seccomp_filter *filter = file->private_data;
|
|
||||||
struct seccomp_knotif *knotif;
|
struct seccomp_knotif *knotif;
|
||||||
|
|
||||||
if (!filter)
|
if (!filter)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
mutex_lock(&filter->notify_lock);
|
mutex_lock(&filter->notify_lock);
|
||||||
|
|
||||||
@ -1142,6 +1141,13 @@ static int seccomp_notify_release(struct inode *inode, struct file *file)
|
|||||||
kfree(filter->notif);
|
kfree(filter->notif);
|
||||||
filter->notif = NULL;
|
filter->notif = NULL;
|
||||||
mutex_unlock(&filter->notify_lock);
|
mutex_unlock(&filter->notify_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seccomp_notify_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct seccomp_filter *filter = file->private_data;
|
||||||
|
|
||||||
|
seccomp_notify_detach(filter);
|
||||||
__put_seccomp_filter(filter);
|
__put_seccomp_filter(filter);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1581,6 +1587,7 @@ out_put_fd:
|
|||||||
listener_f->private_data = NULL;
|
listener_f->private_data = NULL;
|
||||||
fput(listener_f);
|
fput(listener_f);
|
||||||
put_unused_fd(listener);
|
put_unused_fd(listener);
|
||||||
|
seccomp_notify_detach(prepared);
|
||||||
} else {
|
} else {
|
||||||
fd_install(listener, listener_f);
|
fd_install(listener, listener_f);
|
||||||
ret = listener;
|
ret = listener;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user