lkml.org 
[lkml]   [2023]   [Feb]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject[PATCH 1/6] seccomp: don't use semaphore and wait_queue together
    From
    The main reason is to use new wake_up helpers that will be added in the
    following patches. But here 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 can wake up one waiter and
    up(&match->notif->request) can wake up one more.

    Signed-off-by: Andrei Vagin <avagin@google.com>
    ---
    kernel/seccomp.c | 41 ++++++++++++++++++++++++++++++++++++-----
    1 file changed, 36 insertions(+), 5 deletions(-)

    diff --git a/kernel/seccomp.c b/kernel/seccomp.c
    index e9852d1b4a5e..876022e9c88c 100644
    --- a/kernel/seccomp.c
    +++ b/kernel/seccomp.c
    @@ -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);

    --
    2.39.1.456.gfc5497dd1b-goog
    \
     
     \ /
      Last update: 2023-03-27 00:06    [W:3.538 / U:0.232 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site