Skip to content

Commit 4943b66

Browse files
avaginkees
authored andcommitted
seccomp: don't use semaphore and wait_queue together
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 <[email protected]> Acked-by: "Peter Zijlstra (Intel)" <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent fdf0eaf commit 4943b66

File tree

1 file changed

+36
-5
lines changed

1 file changed

+36
-5
lines changed

kernel/seccomp.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ struct seccomp_kaddfd {
145145
* @notifications: A list of struct seccomp_knotif elements.
146146
*/
147147
struct notification {
148-
struct semaphore request;
148+
atomic_t requests;
149149
u64 next_id;
150150
struct list_head notifications;
151151
};
@@ -1116,7 +1116,7 @@ static int seccomp_do_user_notification(int this_syscall,
11161116
list_add_tail(&n.list, &match->notif->notifications);
11171117
INIT_LIST_HEAD(&n.addfd);
11181118

1119-
up(&match->notif->request);
1119+
atomic_inc(&match->notif->requests);
11201120
wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM);
11211121

11221122
/*
@@ -1450,6 +1450,37 @@ find_notification(struct seccomp_filter *filter, u64 id)
14501450
return NULL;
14511451
}
14521452

1453+
static int recv_wake_function(wait_queue_entry_t *wait, unsigned int mode, int sync,
1454+
void *key)
1455+
{
1456+
/* Avoid a wakeup if event not interesting for us. */
1457+
if (key && !(key_to_poll(key) & (EPOLLIN | EPOLLERR)))
1458+
return 0;
1459+
return autoremove_wake_function(wait, mode, sync, key);
1460+
}
1461+
1462+
static int recv_wait_event(struct seccomp_filter *filter)
1463+
{
1464+
DEFINE_WAIT_FUNC(wait, recv_wake_function);
1465+
int ret;
1466+
1467+
if (atomic_dec_if_positive(&filter->notif->requests) >= 0)
1468+
return 0;
1469+
1470+
for (;;) {
1471+
ret = prepare_to_wait_event(&filter->wqh, &wait, TASK_INTERRUPTIBLE);
1472+
1473+
if (atomic_dec_if_positive(&filter->notif->requests) >= 0)
1474+
break;
1475+
1476+
if (ret)
1477+
return ret;
1478+
1479+
schedule();
1480+
}
1481+
finish_wait(&filter->wqh, &wait);
1482+
return 0;
1483+
}
14531484

14541485
static long seccomp_notify_recv(struct seccomp_filter *filter,
14551486
void __user *buf)
@@ -1467,7 +1498,7 @@ static long seccomp_notify_recv(struct seccomp_filter *filter,
14671498

14681499
memset(&unotif, 0, sizeof(unotif));
14691500

1470-
ret = down_interruptible(&filter->notif->request);
1501+
ret = recv_wait_event(filter);
14711502
if (ret < 0)
14721503
return ret;
14731504

@@ -1515,7 +1546,8 @@ static long seccomp_notify_recv(struct seccomp_filter *filter,
15151546
if (should_sleep_killable(filter, knotif))
15161547
complete(&knotif->ready);
15171548
knotif->state = SECCOMP_NOTIFY_INIT;
1518-
up(&filter->notif->request);
1549+
atomic_inc(&filter->notif->requests);
1550+
wake_up_poll(&filter->wqh, EPOLLIN | EPOLLRDNORM);
15191551
}
15201552
mutex_unlock(&filter->notify_lock);
15211553
}
@@ -1777,7 +1809,6 @@ static struct file *init_listener(struct seccomp_filter *filter)
17771809
if (!filter->notif)
17781810
goto out;
17791811

1780-
sema_init(&filter->notif->request, 0);
17811812
filter->notif->next_id = get_random_u64();
17821813
INIT_LIST_HEAD(&filter->notif->notifications);
17831814

0 commit comments

Comments
 (0)