Commit 9a76c0ee authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'seccomp-fixes-v5.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull seccomp fixes from Kees Cook:
 "This fixes a hard-to-hit race condition in the addfd user_notif
  feature of seccomp, visible since v5.9.

  And a small documentation fix"

* tag 'seccomp-fixes-v5.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  seccomp: Refactor notification handler to prepare for new semantics
  Documentation: seccomp: Fix user notification documentation
parents 9d68fe84 ddc47391
...@@ -250,14 +250,14 @@ Users can read via ``ioctl(SECCOMP_IOCTL_NOTIF_RECV)`` (or ``poll()``) on a ...@@ -250,14 +250,14 @@ Users can read via ``ioctl(SECCOMP_IOCTL_NOTIF_RECV)`` (or ``poll()``) on a
seccomp notification fd to receive a ``struct seccomp_notif``, which contains seccomp notification fd to receive a ``struct seccomp_notif``, which contains
five members: the input length of the structure, a unique-per-filter ``id``, five members: the input length of the structure, a unique-per-filter ``id``,
the ``pid`` of the task which triggered this request (which may be 0 if the the ``pid`` of the task which triggered this request (which may be 0 if the
task is in a pid ns not visible from the listener's pid namespace), a ``flags`` task is in a pid ns not visible from the listener's pid namespace). The
member which for now only has ``SECCOMP_NOTIF_FLAG_SIGNALED``, representing notification also contains the ``data`` passed to seccomp, and a filters flag.
whether or not the notification is a result of a non-fatal signal, and the The structure should be zeroed out prior to calling the ioctl.
``data`` passed to seccomp. Userspace can then make a decision based on this
information about what to do, and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a Userspace can then make a decision based on this information about what to do,
response, indicating what should be returned to userspace. The ``id`` member of and ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` a response, indicating what should be
``struct seccomp_notif_resp`` should be the same ``id`` as in ``struct returned to userspace. The ``id`` member of ``struct seccomp_notif_resp`` should
seccomp_notif``. be the same ``id`` as in ``struct seccomp_notif``.
It is worth noting that ``struct seccomp_data`` contains the values of register It is worth noting that ``struct seccomp_data`` contains the values of register
arguments to the syscall, but does not contain pointers to memory. The task's arguments to the syscall, but does not contain pointers to memory. The task's
......
...@@ -1105,28 +1105,30 @@ static int seccomp_do_user_notification(int this_syscall, ...@@ -1105,28 +1105,30 @@ static int seccomp_do_user_notification(int this_syscall,
up(&match->notif->request); up(&match->notif->request);
wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM); wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM);
mutex_unlock(&match->notify_lock);
/* /*
* This is where we wait for a reply from userspace. * This is where we wait for a reply from userspace.
*/ */
wait: do {
err = wait_for_completion_interruptible(&n.ready); mutex_unlock(&match->notify_lock);
mutex_lock(&match->notify_lock); err = wait_for_completion_interruptible(&n.ready);
if (err == 0) { mutex_lock(&match->notify_lock);
/* Check if we were woken up by a addfd message */ if (err != 0)
goto interrupted;
addfd = list_first_entry_or_null(&n.addfd, addfd = list_first_entry_or_null(&n.addfd,
struct seccomp_kaddfd, list); struct seccomp_kaddfd, list);
if (addfd && n.state != SECCOMP_NOTIFY_REPLIED) { /* Check if we were woken up by a addfd message */
if (addfd)
seccomp_handle_addfd(addfd); seccomp_handle_addfd(addfd);
mutex_unlock(&match->notify_lock);
goto wait;
}
ret = n.val;
err = n.error;
flags = n.flags;
}
} while (n.state != SECCOMP_NOTIFY_REPLIED);
ret = n.val;
err = n.error;
flags = n.flags;
interrupted:
/* If there were any pending addfd calls, clear them out */ /* If there were any pending addfd calls, clear them out */
list_for_each_entry_safe(addfd, tmp, &n.addfd, list) { list_for_each_entry_safe(addfd, tmp, &n.addfd, list) {
/* The process went away before we got a chance to handle it */ /* The process went away before we got a chance to handle it */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment