seccomp: Add find_notification helper

This adds a helper which can iterate through a seccomp_filter to
find a notification matching an ID. It removes several replicated
chunks of code.

Signed-off-by: Sargun Dhillon <sargun@sargun.me>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: Tycho Andersen <tycho@tycho.ws>
Cc: Matt Denton <mpdenton@google.com>
Cc: Kees Cook <keescook@google.com>,
Cc: Jann Horn <jannh@google.com>,
Cc: Robert Sesek <rsesek@google.com>,
Cc: Chris Palmer <palmer@google.com>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Tycho Andersen <tycho@tycho.ws>
Link: https://lore.kernel.org/r/20200601112532.150158-1-sargun@sargun.me
Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
Sargun Dhillon 2020-06-01 04:25:32 -07:00 committed by Kees Cook
parent c818c03b66
commit 9f87dcf14b

View File

@ -41,6 +41,7 @@
#include <linux/tracehook.h> #include <linux/tracehook.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/anon_inodes.h> #include <linux/anon_inodes.h>
#include <linux/lockdep.h>
enum notify_state { enum notify_state {
SECCOMP_NOTIFY_INIT, SECCOMP_NOTIFY_INIT,
@ -1024,6 +1025,23 @@ static int seccomp_notify_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
/* must be called with notif_lock held */
static inline struct seccomp_knotif *
find_notification(struct seccomp_filter *filter, u64 id)
{
struct seccomp_knotif *cur;
lockdep_assert_held(&filter->notify_lock);
list_for_each_entry(cur, &filter->notif->notifications, list) {
if (cur->id == id)
return cur;
}
return NULL;
}
static long seccomp_notify_recv(struct seccomp_filter *filter, static long seccomp_notify_recv(struct seccomp_filter *filter,
void __user *buf) void __user *buf)
{ {
@ -1081,15 +1099,8 @@ static long seccomp_notify_recv(struct seccomp_filter *filter,
* may have died when we released the lock, so we need to make * may have died when we released the lock, so we need to make
* sure it's still around. * sure it's still around.
*/ */
knotif = NULL;
mutex_lock(&filter->notify_lock); mutex_lock(&filter->notify_lock);
list_for_each_entry(cur, &filter->notif->notifications, list) { knotif = find_notification(filter, unotif.id);
if (cur->id == unotif.id) {
knotif = cur;
break;
}
}
if (knotif) { if (knotif) {
knotif->state = SECCOMP_NOTIFY_INIT; knotif->state = SECCOMP_NOTIFY_INIT;
up(&filter->notif->request); up(&filter->notif->request);
@ -1104,7 +1115,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter,
void __user *buf) void __user *buf)
{ {
struct seccomp_notif_resp resp = {}; struct seccomp_notif_resp resp = {};
struct seccomp_knotif *knotif = NULL, *cur; struct seccomp_knotif *knotif;
long ret; long ret;
if (copy_from_user(&resp, buf, sizeof(resp))) if (copy_from_user(&resp, buf, sizeof(resp)))
@ -1121,13 +1132,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter,
if (ret < 0) if (ret < 0)
return ret; return ret;
list_for_each_entry(cur, &filter->notif->notifications, list) { knotif = find_notification(filter, resp.id);
if (cur->id == resp.id) {
knotif = cur;
break;
}
}
if (!knotif) { if (!knotif) {
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
@ -1153,7 +1158,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter,
static long seccomp_notify_id_valid(struct seccomp_filter *filter, static long seccomp_notify_id_valid(struct seccomp_filter *filter,
void __user *buf) void __user *buf)
{ {
struct seccomp_knotif *knotif = NULL; struct seccomp_knotif *knotif;
u64 id; u64 id;
long ret; long ret;
@ -1164,16 +1169,12 @@ static long seccomp_notify_id_valid(struct seccomp_filter *filter,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = -ENOENT; knotif = find_notification(filter, id);
list_for_each_entry(knotif, &filter->notif->notifications, list) { if (knotif && knotif->state == SECCOMP_NOTIFY_SENT)
if (knotif->id == id) { ret = 0;
if (knotif->state == SECCOMP_NOTIFY_SENT) else
ret = 0; ret = -ENOENT;
goto out;
}
}
out:
mutex_unlock(&filter->notify_lock); mutex_unlock(&filter->notify_lock);
return ret; return ret;
} }