@@ -0,0 +1,247 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====================
+Pidfd spawn builders
+====================
+
+Pidfd spawn builders create a new process image with kernel-mediated setup.
+They do not expose a userspace child stub between process creation and exec.
+
+The interface is::
+
+ int fd = pidfd_open(0, PIDFD_EMPTY);
+
+ /* Optional executable-path staging. */
+ pidfd_config(fd, PIDFD_CONFIG_SET_STRING,
+ PIDFD_CONFIG_KEY_PATH, path, 0);
+
+ pidfd_spawn_run(fd, &args, sizeof(args));
+
+The same fd starts as a taskless pidfs object and becomes the child's pidfd
+when a task is created. The current implementation supports an executable
+path, argv, envp, and ordered ``DUP2``, ``CLOSE_RANGE``, and ``FCHDIR`` file
+actions.
+
+Opening a builder
+=================
+
+``pidfd_open(0, PIDFD_EMPTY)`` returns a close-on-exec builder fd.
+``PIDFD_NONBLOCK`` may be combined with ``PIDFD_EMPTY``. Other flags are
+rejected. ``PIDFD_EMPTY`` is rejected for a nonzero pid.
+
+Opening the builder allocates a pidfs inode and builder state. It does not
+allocate a ``struct pid`` or task, and does not charge ``RLIMIT_NPROC`` or the
+pids cgroup controller. PID allocation and process-count accounting occur when
+``pidfd_spawn_run()`` calls the normal task-creation path.
+
+The pidfs inode has a stable identity before and after task creation. A pidfd
+opened from the eventual numeric pid refers to the same pidfs inode. A poll or
+epoll registration made while the fd is taskless remains attached across
+publication and can report the child's eventual exit.
+
+Process-dependent pidfd operations return ``ESRCH`` while the builder is
+taskless. This includes signal delivery, ``pidfd_getfd()``,
+``PIDFD_GET_INFO``, namespace ioctls, ``setns()``, process memory operations,
+and process-dependent pidfs xattrs. Argument validation may fail before the
+taskless-state check. ``poll()`` reports no event while the builder may still
+publish a task. After a terminal taskless failure, ``poll()`` and ``epoll``
+report ``POLLERR | POLLHUP`` and wake registrations made before the failure.
+Inode-only operations such as ``FS_IOC_GETVERSION`` remain available.
+
+The builder state follows the lifetime of the pidfs inode. Duplicated or
+reopened descriptors and VFS references to that inode keep it alive. Releasing
+the final reference before a run discards the taskless builder without
+creating a process.
+
+Source state and authority
+==========================
+
+The current mode is source-based. The child is created from the calling
+process at run time. State changed after ``pidfd_open()`` but before
+``pidfd_spawn_run()``, including the current directory and file descriptor
+table, is therefore visible to normal process creation. Non-close-on-exec file
+descriptors remain available to the new image unless a file action changes
+them. The exec path applies ``FD_CLOEXEC`` normally.
+
+File and filesystem state are private child copies before file actions run.
+The current backend shares the address space only for its internal
+vfork-style setup and replaces it during exec. Applications must not depend on
+that backend detail.
+
+Configuration and run authority is bound to the mm, exact credential object,
+and child PID namespace recorded when the builder is opened. Passing the fd
+through ``SCM_RIGHTS`` or another fd-passing mechanism does not by itself
+delegate authority to configure or run it. A rejected authority check does not
+consume the builder.
+
+Configuring an executable path
+==============================
+
+The optional configuration command is::
+
+ pidfd_config(fd, PIDFD_CONFIG_SET_STRING,
+ PIDFD_CONFIG_KEY_PATH, path, 0);
+
+The command copies ``path`` into builder state. Calling it again before a run
+replaces the staged string. The key and value must be valid NUL-terminated
+userspace strings, and ``aux`` must be zero. Unknown commands or keys return
+``EOPNOTSUPP``.
+
+Staging is not required when the run arguments provide ``path``. Supplying a
+run-time path when a path is already staged, or supplying neither form,
+returns ``EINVAL``. This selection is validated before a run-time path pointer
+is dereferenced, so a staged-path conflict takes precedence over a fault in
+that pointer. Relative paths are resolved after ordered file actions from the
+child's resulting working directory. Without an ``FCHDIR`` action, that is
+the working directory copied at run time. The kernel does not search ``PATH``.
+
+Run arguments
+=============
+
+Version 0 of ``struct pidfd_spawn_run_args`` contains:
+
+* ``path``: an optional executable-path pointer;
+* ``argv``: a required argument-vector pointer;
+* ``envp``: an environment-vector pointer, or zero for an empty environment;
+* ``actions``, ``nr_actions``, and ``action_size``: an optional ordered
+ file-action array.
+
+``flags`` and all reserved fields must be zero. The syscall size must be at
+least ``PIDFD_SPAWN_RUN_SIZE_VER0`` and no larger than ``PAGE_SIZE``. Unknown
+trailing bytes in a larger structure must be zero.
+
+``path``, ``argv``, ``envp``, and ``actions`` are full-width userspace virtual
+addresses stored in ``__aligned_u64`` fields on every ABI. Native calls must
+fit the native pointer width. Compat calls must fit ``compat_uptr_t``; nonzero
+upper bits are rejected with ``EFAULT`` before task creation. Entries read
+from compat argv and envp arrays are compat pointers.
+
+File actions
+============
+
+When ``nr_actions`` is zero, ``actions`` and ``action_size`` must also be zero.
+Otherwise ``actions`` must be nonzero and ``action_size`` must be at least
+``PIDFD_SPAWN_ACTION_SIZE_VER0`` and aligned to eight bytes. A larger element
+is accepted only when its unknown tail is zero. The complete action payload is
+limited to 64 KiB; the interface does not impose a fixed action count below
+that byte limit.
+
+Actions execute in array order against child-private file and filesystem
+state before exec:
+
+``PIDFD_SPAWN_ACTION_DUP2``
+ Duplicate ``fd`` onto ``newfd``. If both numbers are equal, clear
+ ``FD_CLOEXEC`` on that descriptor. ``flags`` and reserved fields must be
+ zero.
+
+``PIDFD_SPAWN_ACTION_CLOSE_RANGE``
+ Apply ``close_range(fd, newfd, flags)``. ``newfd`` must not be less than
+ ``fd``. Only ``CLOSE_RANGE_UNSHARE`` and ``CLOSE_RANGE_CLOEXEC`` are
+ accepted.
+
+``PIDFD_SPAWN_ACTION_FCHDIR``
+ Change the child working directory to ``fd``. ``flags``, ``newfd``, and
+ reserved fields must be zero.
+
+An unknown action type returns ``EOPNOTSUPP``. Invalid fields or arguments
+return ``EINVAL``. Errors from applying an otherwise valid action are reported
+as run failures after task publication.
+
+One-shot execution and results
+==============================
+
+After fd type, creator authority, and source ptrace checks succeed, the first
+``pidfd_spawn_run()`` attempt atomically claims the builder before copying its
+run arguments. Argument faults, validation errors, memory-allocation failures,
+process limits, and task-creation failures after that claim are terminal.
+Later configuration and run attempts return ``EBUSY``.
+
+Checks that fail before the claim do not consume the builder. These include an
+invalid fd type, creator-authority mismatch, or an already traced source.
+
+On successful setup and exec, ``pidfd_spawn_run()`` returns the positive child
+pid as seen in the caller's PID namespace. The pidfd remains the stable process
+identity.
+
+A failure before task creation returns a negative error and leaves the fd
+terminal but taskless. Ordinary pidfd operations continue to return ``ESRCH``.
+``poll()`` and ``epoll`` report ``POLLERR | POLLHUP``. The builder cannot be
+retried; a caller must open a new builder.
+
+A setup or exec failure after publication returns a negative error, leaves the
+same fd as the child's pidfd, and makes the child exit with status 127. Normal
+``SIGCHLD``, ``SIG_IGN``, and ``SA_NOCLDWAIT`` rules determine whether it must
+be reaped. ``PIDFD_GET_INFO`` with ``PIDFD_INFO_EXIT`` distinguishes this case
+from a terminal taskless failure.
+
+Internal restart errors after the claim are returned to userspace as
+``EINTR``. The kernel does not automatically restart a consumed run and
+replace its first result with ``EBUSY``.
+
+A fatal signal delivered to the published child determines the child's exit
+status if it wins during setup. It is not reported as an exec setup error, so
+the run can return the positive child pid even when that child exits from the
+signal.
+
+Embryonic process state
+=======================
+
+After task publication and before successful exec completion, the child is in
+an embryonic exec state. It is not yet a normal userspace process image and
+does not have a valid userspace register frame on every architecture.
+
+During this interval:
+
+* direct ptrace access and ``pidfd_getfd()`` are denied;
+* procfs PID lookup and iteration treat the task as absent to other tasks,
+ preventing access to the source address space temporarily shared by the
+ implementation; the embryonic task may resolve its own procfs entries for
+ executable and interpreter lookup;
+* ``PIDFD_GET_INFO`` reports ``PIDFD_COREDUMP_SKIP`` when coredump state is
+ requested;
+* ordinary pidfd identity, signal, wait, and poll mechanisms operate on the
+ published task as their normal permission checks allow.
+
+Successful exec releases the embryonic state before exec event publication. A
+failed setup never exposes the borrowed pre-exec frame to userspace; the child
+exits instead.
+
+Security policy and audit
+=========================
+
+File actions and exec run inside the child kernel path. They do not appear to
+seccomp as separate ``dup2()``, ``close_range()``, ``fchdir()``, or
+``execve()`` syscalls. A source-side seccomp filter can reject
+``pidfd_spawn_run()`` before the builder is claimed. A policy that intends to
+prevent this operation must filter ``pidfd_spawn_run()`` itself; denying only
+the syscall numbers corresponding to its file actions or exec does not mediate
+the equivalent in-kernel work. In particular, an exec-only denylist that
+allows unknown syscalls does not block the initial spawn exec; it must add
+``pidfd_spawn_run()``. A syscall allowlist does not permit the new operation
+until it adds that syscall. Seccomp state inherited by the child remains active
+after exec. LSM checks, including Landlock executable access, still mediate the
+underlying exec.
+
+Audit records the source syscall transaction and a separate
+``AUDIT_PIDFD_SPAWN`` child transaction for executable lookup and exec
+arguments. The child does not emit a synthetic second ``AUDIT_SYSCALL``
+record. The child transaction is selected using the originating
+``pidfd_spawn_run()`` syscall number, so an existing exit rule that names only
+``execve()`` or ``execveat()`` does not select it. Such rules must also select
+``pidfd_spawn_run()`` with the current audit model. File actions are not
+emitted as decoded per-action audit records.
+
+An already traced source is rejected before the claim. The current backend
+does not implement ptrace auto-attach events for the created child.
+
+Current limitations
+===================
+
+The interface does not yet implement the full ``posix_spawn()`` surface. It
+lacks open and close file actions, resetids, signal mask and default controls,
+scheduler attributes, affinity, process groups, sessions, explicit cgroup
+placement, ``PATH`` search, and exec by fd.
+
+It also does not provide pristine or no-source process creation, executable
+metadata caching, or reusable spawn templates. The current implementation is
+source-based and uses the existing vfork/exec machinery internally.