[1/5] seccomp: don't use semaphore and wait_queue together
Commit Message
Here is no reason to use two different primitives that do similar things.
Signed-off-by: Andrei Vagin <avagin@gmail.com>
---
kernel/seccomp.c | 41 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)
Comments
On October 19, 2022 6:10:44 PM PDT, Andrei Vagin <avagin@gmail.com> wrote:
>Here is no reason to use two different primitives that do similar things.
>
>Signed-off-by: Andrei Vagin <avagin@gmail.com>
>---
> kernel/seccomp.c | 41 ++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 36 insertions(+), 5 deletions(-)
The commit log does not justify adding 29 lines to "do similar things". :) Can you describe the rationale and benefits here a bit more? I assume this to use the the future new wake_up helper?
On Wed, Oct 19, 2022 at 10:10:44PM -0700, Kees Cook wrote:
> On October 19, 2022 6:10:44 PM PDT, Andrei Vagin <avagin@gmail.com> wrote:
> >Here is no reason to use two different primitives that do similar things.
> >
> >Signed-off-by: Andrei Vagin <avagin@gmail.com>
> >---
> > kernel/seccomp.c | 41 ++++++++++++++++++++++++++++++++++++-----
> > 1 file changed, 36 insertions(+), 5 deletions(-)
>
> The commit log does not justify adding 29 lines to "do similar
> things". :) Can you describe the rationale and benefits here a bit
> more? I assume this to use the the future new wake_up helper?
The main reason is to use new wake_up helpers, but there are a few
other reasons:
* if we use two different ways, we always need to call them both. This
patch fixes seccomp_notify_recv where we forgot to call wake_up_poll
in the error path.
* If we use one primitive, we can control how many waiters are woken up
for each request. Our goal is to wake up just one that will handle a
request. Right now, wake_up_poll may wake up one waiter and
up(&match->notif->request) may wake up one more.
I will update the commit message. Thanks!
>
>
> --
> Kees Cook
@@ -145,7 +145,7 @@ struct seccomp_kaddfd {
* @notifications: A list of struct seccomp_knotif elements.
*/
struct notification {
- struct semaphore request;
+ atomic_t requests;
u64 next_id;
struct list_head notifications;
};
@@ -1116,7 +1116,7 @@ static int seccomp_do_user_notification(int this_syscall,
list_add_tail(&n.list, &match->notif->notifications);
INIT_LIST_HEAD(&n.addfd);
- up(&match->notif->request);
+ atomic_add(1, &match->notif->requests);
wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM);
/*
@@ -1450,6 +1450,37 @@ find_notification(struct seccomp_filter *filter, u64 id)
return NULL;
}
+static int recv_wake_function(wait_queue_entry_t *wait, unsigned int mode, int sync,
+ void *key)
+{
+ /* Avoid a wakeup if event not interesting for us. */
+ if (key && !(key_to_poll(key) & (EPOLLIN | EPOLLERR)))
+ return 0;
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+
+static int recv_wait_event(struct seccomp_filter *filter)
+{
+ DEFINE_WAIT_FUNC(wait, recv_wake_function);
+ int ret;
+
+ if (atomic_add_unless(&filter->notif->requests, -1, 0) != 0)
+ return 0;
+
+ for (;;) {
+ ret = prepare_to_wait_event(&filter->wqh, &wait, TASK_INTERRUPTIBLE);
+
+ if (atomic_add_unless(&filter->notif->requests, -1, 0) != 0)
+ break;
+
+ if (ret)
+ return ret;
+
+ schedule();
+ }
+ finish_wait(&filter->wqh, &wait);
+ return 0;
+}
static long seccomp_notify_recv(struct seccomp_filter *filter,
void __user *buf)
@@ -1467,7 +1498,7 @@ static long seccomp_notify_recv(struct seccomp_filter *filter,
memset(&unotif, 0, sizeof(unotif));
- ret = down_interruptible(&filter->notif->request);
+ ret = recv_wait_event(filter);
if (ret < 0)
return ret;
@@ -1515,7 +1546,8 @@ static long seccomp_notify_recv(struct seccomp_filter *filter,
if (should_sleep_killable(filter, knotif))
complete(&knotif->ready);
knotif->state = SECCOMP_NOTIFY_INIT;
- up(&filter->notif->request);
+ atomic_add(1, &filter->notif->requests);
+ wake_up_poll(&filter->wqh, EPOLLIN | EPOLLRDNORM);
}
mutex_unlock(&filter->notify_lock);
}
@@ -1777,7 +1809,6 @@ static struct file *init_listener(struct seccomp_filter *filter)
if (!filter->notif)
goto out;
- sema_init(&filter->notif->request, 0);
filter->notif->next_id = get_random_u64();
INIT_LIST_HEAD(&filter->notif->notifications);