mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH 0/9] seccomp: report the result of continued system calls
@ 2026-10-20  0:11 Cong Wang
  2026-10-20  0:11 ` [RFC PATCH 1/9] seccomp: add result records to the notification listener Cong Wang
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Cong Wang @ 2026-10-20  0:11 UTC (permalink / raw)
  To: linux-kernel; +Cc: Andy Lutomirski, Kees Cook, Will Drewry, Christian Brauner

From: Cong Wang <cwang@multikernel.io>

A seccomp user notification supervisor that continues a fork never
learns whether it succeeded or which task it created, so it cannot track
the tasks below it. Today the only way is ptrace fork events, which take
the one tracer slot from every task, may be forbidden by Yama or an LSM,
report nothing for a failed fork, interfere with signals and waitpid(),
and cost several stops per fork.

Sandlock [1] hits exactly this. It is an unprivileged process sandbox
built on seccomp user notification, with no cgroups to count tasks, so
it must see every fork itself and is left with ptrace and its problems.

This series lets the supervisor ask for the result of a continued
system call:

  - SECCOMP_USER_NOTIF_FLAG_RESULT, given with CONTINUE, queues a one-way
    result record on the listener once the call completes. It is read
    with SECCOMP_IOCTL_NOTIF_RECV like any notification, flagged with
    SECCOMP_NOTIF_FLAG_RESULT, and carries the id of the continued
    notification and the call's return value.

  - For the fork family, the record also carries the new task's pid in
    the listener's pid namespace and its pidfs inode number, which is
    never reused. The supervisor can open a pidfd for exactly that task
    with open_by_handle_at(FD_PIDFS_ROOT, ...), unprivileged, or learn
    that it has already exited. The record is queued before the new task
    first runs and records are received before notifications, so the
    supervisor always hears of a task before it hears from it.

  - SECCOMP_USER_NOTIF_FLAG_HOLD, given with RESULT, reports the result
    as a notification the supervisor must answer, and the task waits
    until it does. For a fork, the new task does not run until then
    either, so the supervisor can act on it before its first
    instruction.

The interface is generic; only the fork family is supported so far.
Results are reported from task work on the way back to user space,
which needs nothing per system call. A successful fork is the one
exception: it is reported in kernel_clone() just before the child is
woken, which is the only point where both ordering and the child's
identity can be guaranteed. Every other system call is refused with
EINVAL, which is also what older kernels return, so the flags are easy
to probe and can be extended to more calls without new uAPI.

struct seccomp_notif keeps its size: the result shares a union with
struct seccomp_data, so the ioctl numbers and SECCOMP_GET_NOTIF_SIZES
are unchanged. The record is allocated by SEND and charged to the
supervisor, so the system call itself never allocates and a record can
never be lost after the point of no return.

Tested on x86_64 in QEMU with lockdep, KASAN and kmemleak: the full
seccomp_bpf selftest, the new tests as an unprivileged user, and fork
result records from an ia32 task.

[1] https://github.com/multikernel/sandlock

---

Cong Wang (9):
  seccomp: add result records to the notification listener
  seccomp: add __NR_seccomp_* aliases for the fork family
  seccomp: report the result of a continued system call
  seccomp: report the result of a continued fork
  seccomp: factor out the user notification queue and wait
  seccomp: add SECCOMP_USER_NOTIF_FLAG_HOLD
  selftests/seccomp: test fork result records
  selftests/seccomp: test held fork results
  Documentation: seccomp: describe system call result records

 .../userspace-api/seccomp_filter.rst          | 117 +++-
 arch/Kconfig                                  |   6 +
 arch/x86/include/asm/seccomp.h                |   4 +
 include/asm-generic/seccomp.h                 |  26 +
 include/linux/seccomp.h                       |   4 +
 include/linux/seccomp_types.h                 |   6 +
 include/uapi/linux/seccomp.h                  |  57 +-
 kernel/fork.c                                 |   3 +
 kernel/seccomp.c                              | 461 ++++++++++++--
 tools/testing/selftests/seccomp/seccomp_bpf.c | 579 ++++++++++++++++++
 10 files changed, 1218 insertions(+), 45 deletions(-)


base-commit: c03c1a14507dfaf8b856c2608f9ac216021fc222
-- 
2.43.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-10-20  0:11 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-20  0:11 [RFC PATCH 0/9] seccomp: report the result of continued system calls Cong Wang
2026-10-20  0:11 ` [RFC PATCH 1/9] seccomp: add result records to the notification listener Cong Wang
2026-10-20  0:11 ` [RFC PATCH 2/9] seccomp: add __NR_seccomp_* aliases for the fork family Cong Wang
2026-10-20  0:11 ` [RFC PATCH 3/9] seccomp: report the result of a continued system call Cong Wang
2026-10-20  0:11 ` [RFC PATCH 4/9] seccomp: report the result of a continued fork Cong Wang
2026-10-20  0:11 ` [RFC PATCH 5/9] seccomp: factor out the user notification queue and wait Cong Wang
2026-10-20  0:11 ` [RFC PATCH 6/9] seccomp: add SECCOMP_USER_NOTIF_FLAG_HOLD Cong Wang
2026-10-20  0:11 ` [RFC PATCH 7/9] selftests/seccomp: test fork result records Cong Wang
2026-10-20  0:11 ` [RFC PATCH 8/9] selftests/seccomp: test held fork results Cong Wang
2026-10-20  0:11 ` [RFC PATCH 9/9] Documentation: seccomp: describe system call result records Cong Wang

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®