seccomp: Add find_notification helper
authorSargun Dhillon <sargun@sargun.me>
Mon, 1 Jun 2020 11:25:32 +0000 (04:25 -0700)
committerKees Cook <keescook@chromium.org>
Fri, 10 Jul 2020 23:01:51 +0000 (16:01 -0700)
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>
kernel/seccomp.c

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