summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrei Vagin <avagin@google.com>2024-06-28 02:10:11 +0000
committerKees Cook <kees@kernel.org>2024-06-28 09:37:11 -0700
commit95036a79e7b56178e2fa9c485114be61d24c1695 (patch)
treeafd265cb825a9b1c28976cd1e5f03d6f2d4e42ba
parentc3f38fa61af77b49866b006939479069cd451173 (diff)
seccomp: interrupt SECCOMP_IOCTL_NOTIF_RECV when all users have exited
SECCOMP_IOCTL_NOTIF_RECV promptly returns when a seccomp filter becomes unused, as a filter without users can't trigger any events. Previously, event listeners had to rely on epoll to detect when all processes had exited. The change is based on the 'commit 99cdb8b9a573 ("seccomp: notify about unused filter")' which implemented (E)POLLHUP notifications. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Andrei Vagin <avagin@google.com> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Link: https://lore.kernel.org/r/20240628021014.231976-2-avagin@google.com Reviewed-by: Tycho Andersen <tandersen@netflix.com> Signed-off-by: Kees Cook <kees@kernel.org>
-rw-r--r--kernel/seccomp.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index e30b60b57614..60990264fef0 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1466,7 +1466,7 @@ static int recv_wake_function(wait_queue_entry_t *wait, unsigned int mode, int s
void *key)
{
/* Avoid a wakeup if event not interesting for us. */
- if (key && !(key_to_poll(key) & (EPOLLIN | EPOLLERR)))
+ if (key && !(key_to_poll(key) & (EPOLLIN | EPOLLERR | EPOLLHUP)))
return 0;
return autoremove_wake_function(wait, mode, sync, key);
}
@@ -1476,6 +1476,9 @@ static int recv_wait_event(struct seccomp_filter *filter)
DEFINE_WAIT_FUNC(wait, recv_wake_function);
int ret;
+ if (refcount_read(&filter->users) == 0)
+ return 0;
+
if (atomic_dec_if_positive(&filter->notif->requests) >= 0)
return 0;
@@ -1484,6 +1487,8 @@ static int recv_wait_event(struct seccomp_filter *filter)
if (atomic_dec_if_positive(&filter->notif->requests) >= 0)
break;
+ if (refcount_read(&filter->users) == 0)
+ break;
if (ret)
return ret;