From: Cong Wang <xiyou.wangcong@gmail.com>
To: Kees Cook <kees@kernel.org>, linux-kernel@vger.kernel.org
Cc: Andy Lutomirski <luto@amacapital.net>,
Will Drewry <wad@chromium.org>,
Christian Brauner <brauner@kernel.org>,
Cong Wang <cwang@multikernel.io>
Subject: [RFC PATCH v2 3/3] Documentation: seccomp: document SECCOMP_IOCTL_NOTIF_INJECT
Date: Thu, 14 May 2026 21:27:38 -0700 [thread overview]
Message-ID: <20260515042738.1723296-4-xiyou.wangcong@gmail.com> (raw)
In-Reply-To: <20260515042738.1723296-1-xiyou.wangcong@gmail.com>
From: Cong Wang <cwang@multikernel.io>
Add a "Syscall Injection" subsection to the user-notification chapter
covering the motivation (closing the documented TOCTOU window for
unprivileged supervisors), the substitute-syscall flow via
SECCOMP_IOCTL_NOTIF_INJECT and SECCOMP_USER_NOTIF_FLAG_INJECTED, the
ptrace-shaped struct layout, the kernel-buffer-backed pointer
arguments, the listener-fd capability model, and the relationship to
ptrace's existing register/memory manipulation.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Cong Wang <cwang@multikernel.io>
---
.../userspace-api/seccomp_filter.rst | 42 +++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation/userspace-api/seccomp_filter.rst
index cff0fa7f3175..9057505b2b92 100644
--- a/Documentation/userspace-api/seccomp_filter.rst
+++ b/Documentation/userspace-api/seccomp_filter.rst
@@ -289,6 +289,48 @@ above in this document: all arguments being read from the tracee's memory
should be read into the tracer's memory before any policy decisions are made.
This allows for an atomic decision on syscall arguments.
+Syscall Injection
+-----------------
+
+For unprivileged supervisors, ``ptrace()`` and ``/proc/pid/mem`` are not
+available, and reading the tracee's memory via ``process_vm_readv()``
+remains racy: a sibling thread or ``CLONE_VM`` peer can mutate pointer-arg
+buffers between the supervisor's read and the kernel's re-read on
+``SECCOMP_USER_NOTIF_FLAG_CONTINUE``. ``SECCOMP_IOCTL_NOTIF_INJECT``
+closes that race by letting the supervisor describe a substitute syscall
+(``nr`` plus ``args[6]``, mirroring ``ptrace_syscall_info.entry``) whose
+pointer arguments are backed by a kernel-side copy of supervisor-supplied
+bytes rather than the tracee's user mm.
+
+The supervisor receives a notification as today, then issues
+``ioctl(SECCOMP_IOCTL_NOTIF_INJECT, &inj)`` with a
+``struct seccomp_notif_inject`` describing the substitute. Each pointer-
+shaped argument is encoded as a byte offset into ``inj.buf`` (a user
+buffer the kernel copies in at attach time); the ``args_in_buf_mask``
+field flags which ``args[i]`` are offsets versus raw scalar values.
+The substitute is consumed by ``ioctl(SECCOMP_IOCTL_NOTIF_SEND)`` with
+``SECCOMP_USER_NOTIF_FLAG_INJECTED``: the trapped task wakes, dispatches
+into the matching kernel-mode helper (``filp_open`` for ``openat``,
+``kernel_bind`` for ``bind``, ``kernel_write`` for ``write``), and the
+helper's return value becomes the trapped syscall's return value.
+
+The trapped task's user mm is never re-read for the substituted syscall,
+so peer mutations after ``SECCOMP_IOCTL_NOTIF_INJECT`` returns have no
+effect.
+
+Injection is gated by listener-fd possession (the same capability model
+as the rest of the user-notification interface) and by an explicit
+kernel-side whitelist of injectable syscalls. The substitute ``nr`` must
+match the trapped syscall's number, preventing a malicious supervisor
+from converting "task tried to bind()" into "kernel does an openat() on
+the task's behalf".
+
+This is intentionally a strict subset of ``PTRACE_SYSCALL`` +
+``PTRACE_POKEDATA`` + ``PTRACE_SETREGSET``: the same kernel capability
+(running a syscall in the trapped task's context with kernel-validated
+args), exposed to unprivileged listener-fd-holding supervisors with a
+narrowed surface and no need for ``CAP_SYS_PTRACE``.
+
Sysctls
=======
--
2.43.0
next prev parent reply other threads:[~2026-05-15 4:27 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-15 4:27 [RFC PATCH v2 0/3] seccomp: SECCOMP_IOCTL_NOTIF_INJECT for race-free unotify Cong Wang
2026-05-15 4:27 ` [RFC PATCH v2 1/3] seccomp: add " Cong Wang
2026-05-15 4:27 ` [RFC PATCH v2 2/3] selftests/seccomp: add seccomp_notif_inject coverage Cong Wang
2026-05-15 4:27 ` Cong Wang [this message]
2026-05-26 18:06 ` [RFC PATCH v2 0/3] seccomp: SECCOMP_IOCTL_NOTIF_INJECT for race-free unotify Cong Wang
2026-05-26 19:03 ` Andy Lutomirski
2026-05-28 17:41 ` Cong Wang
2026-05-28 18:15 ` Andy Lutomirski
2026-05-29 5:07 ` Cong Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260515042738.1723296-4-xiyou.wangcong@gmail.com \
--to=xiyou.wangcong@gmail.com \
--cc=brauner@kernel.org \
--cc=cwang@multikernel.io \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=wad@chromium.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®