seccomp: add the synchronous mode for seccomp_unotify
[linux-block.git] / kernel / seccomp.c
index 1386dcedda1a4d8bbda88d3e8484198f3ff79793..d3fdc0086168f12a77fe3a69bcc3c07906fff2a1 100644 (file)
@@ -143,9 +143,12 @@ struct seccomp_kaddfd {
  *           filter->notify_lock.
  * @next_id: The id of the next request.
  * @notifications: A list of struct seccomp_knotif elements.
+ * @flags: A set of SECCOMP_USER_NOTIF_FD_* flags.
  */
+
 struct notification {
        atomic_t requests;
+       u32 flags;
        u64 next_id;
        struct list_head notifications;
 };
@@ -1117,7 +1120,10 @@ static int seccomp_do_user_notification(int this_syscall,
        INIT_LIST_HEAD(&n.addfd);
 
        atomic_inc(&match->notif->requests);
-       wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM);
+       if (match->notif->flags & SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP)
+               wake_up_poll_on_current_cpu(&match->wqh, EPOLLIN | EPOLLRDNORM);
+       else
+               wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM);
 
        /*
         * This is where we wait for a reply from userspace.
@@ -1593,7 +1599,10 @@ static long seccomp_notify_send(struct seccomp_filter *filter,
        knotif->error = resp.error;
        knotif->val = resp.val;
        knotif->flags = resp.flags;
-       complete(&knotif->ready);
+       if (filter->notif->flags & SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP)
+               complete_on_current_cpu(&knotif->ready);
+       else
+               complete(&knotif->ready);
 out:
        mutex_unlock(&filter->notify_lock);
        return ret;
@@ -1623,6 +1632,22 @@ static long seccomp_notify_id_valid(struct seccomp_filter *filter,
        return ret;
 }
 
+static long seccomp_notify_set_flags(struct seccomp_filter *filter,
+                                   unsigned long flags)
+{
+       long ret;
+
+       if (flags & ~SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP)
+               return -EINVAL;
+
+       ret = mutex_lock_interruptible(&filter->notify_lock);
+       if (ret < 0)
+               return ret;
+       filter->notif->flags = flags;
+       mutex_unlock(&filter->notify_lock);
+       return 0;
+}
+
 static long seccomp_notify_addfd(struct seccomp_filter *filter,
                                 struct seccomp_notif_addfd __user *uaddfd,
                                 unsigned int size)
@@ -1752,6 +1777,8 @@ static long seccomp_notify_ioctl(struct file *file, unsigned int cmd,
        case SECCOMP_IOCTL_NOTIF_ID_VALID_WRONG_DIR:
        case SECCOMP_IOCTL_NOTIF_ID_VALID:
                return seccomp_notify_id_valid(filter, buf);
+       case SECCOMP_IOCTL_NOTIF_SET_FLAGS:
+               return seccomp_notify_set_flags(filter, arg);
        }
 
        /* Extensible Argument ioctls */