A sandboxed process may need an operation that cannot be represented safely as a permanent seccomp allow rule. The operation can depend on runtime policy, external state, or a resource that only a more privileged component should inspect. Allowing the system call unconditionally widens the sandbox, while rejecting it removes required functionality.
Linux seccomp user notification provides a mediation point for this case. A seccomp filter can return SECCOMP_RET_USER_NOTIF for selected calls. The kernel then blocks the triggering task and emits a notification through a listener file descriptor. A supervisor reads that notification and sends a response that determines the immediate disposition of the intercepted call.
This mechanism changes the location of a decision, but it does not turn the supervisor into a transparent kernel reference monitor. The notification carries a snapshot of syscall metadata, while process memory and descriptor state can remain mutable. Security therefore depends on both the seccomp policy and the supervisor’s treatment of state that can change between inspection and action.
The listener descriptor is an authority boundary
A filter installed with SECCOMP_FILTER_FLAG_NEW_LISTENER can return a listener file descriptor to the installing process. Notifications generated by SECCOMP_RET_USER_NOTIF are received through this descriptor using seccomp notification ioctls.
The descriptor is not merely an event stream. A process able to operate the listener can influence whether intercepted calls fail, return a supplied value, or continue through the kernel when continuation is requested and supported by the response flags. Control of the listener therefore belongs in the system’s authority model.
A common architecture separates the constrained task from a supervisor that retains the listener. The constrained task executes under the filter; the supervisor owns policy data and receives notification records. Descriptor transfer, process lifetime, and supervisor privilege become part of the security boundary rather than incidental implementation details.
The kernel does not infer application policy. It reports the intercepted syscall number, arguments, task identity information, and a notification identifier. The supervisor supplies the policy interpretation.
Notification identifiers protect a moving task state
A notification has an identifier that the supervisor can validate with SECCOMP_IOCTL_NOTIF_ID_VALID. This matters because the target task can exit or a notification can cease to be current while the supervisor performs work.
Identifier validation provides a way to check that a notification still refers to a live pending request before a supervisor commits an external side effect. It does not freeze all user-space state associated with the request. A pointer passed as a syscall argument still points into memory controlled according to the target process’s memory-sharing model.
That distinction is central for pathnames, socket address structures, and other pointer-based arguments. Reading target memory once and later acting on the copied interpretation can create a time-of-check to time-of-use gap if the eventual operation consults target memory again. A supervisor must avoid treating mutable user memory as an immutable capability.
The notification identifier solves notification lifetime ambiguity. It does not solve arbitrary races in application memory.
Continuing a call preserves kernel semantics but also preserves races
A supervisor can respond with SECCOMP_USER_NOTIF_FLAG_CONTINUE on kernels that support this behavior. The kernel then continues execution of the intercepted system call instead of returning a supervisor-supplied result.
Continuation is useful when policy needs to approve an operation while leaving the actual syscall implementation to the kernel. It also creates a precise limitation: the supervisor’s inspection and the kernel’s later use of syscall arguments are separate moments. If an argument refers to mutable memory, the value inspected by the supervisor can differ from the value consumed after continuation.
For that reason, continuation is not equivalent to atomically approving the exact object that the supervisor inspected. Policies based on pointer-referenced strings or structures need a design that accounts for mutation. A check that compares a pathname string and then continues openat() can be unsafe if another thread can alter the string before the kernel copies it.
The seccomp documentation explicitly treats continuation as an operation that requires care. Its presence is valuable, but its security property is narrower than an atomic check-and-execute primitive.
Injected descriptors can replace pathname replay
For some file-access designs, SECCOMP_IOCTL_NOTIF_ADDFD offers a stronger pattern than approving a pathname and continuing the original open operation. A supervisor can open a resource under its own controlled resolution policy, then install a file descriptor into the target process in association with the pending notification.
This changes the object passed across the boundary. Instead of relying on a mutable pathname to identify the same object twice, the supervisor can resolve the resource once and transfer a kernel file reference. The supervisor can then return an appropriate descriptor number as the intercepted call’s result when the design matches the emulated syscall contract.
Descriptor injection still requires careful policy. The supervisor’s own filesystem namespace, credentials, directory descriptors, and path-resolution rules determine what it can open. Giving the target a descriptor also grants the operations permitted by that descriptor and by later kernel checks. The mechanism removes one class of pathname replay race; it does not define the resource policy by itself.
SECCOMP_IOCTL_NOTIF_ADDFD is also kernel-version dependent. A deployment must verify support rather than treating the ioctl as a property of all seccomp user-notification implementations.
Emulation must match the intercepted ABI contract
A supervisor can send a response containing an error or a return value. That facility makes syscall emulation possible, but correctness depends on the exact ABI expected by the intercepted program.
Returning a value that merely looks successful can violate application assumptions if the syscall normally creates kernel state. A fabricated descriptor number, for example, is not equivalent to installing a real descriptor. Calls that create handles, modify process state, or establish kernel objects need corresponding state changes if they are to be emulated rather than continued.
This is a security concern as well as a compatibility concern. Incomplete emulation can move application control flow into states that the surrounding design did not anticipate. The narrowest reliable use cases are those where the supervisor can produce the required kernel object or where failure policy is sufficient.
Architecture should therefore distinguish three actions: deny the call, emulate its result with all required state, or permit kernel execution through continuation. Those actions have different race properties and different authority requirements.
User notification is not a privilege escalation primitive
Seccomp user notification does not inherently grant the target task the supervisor’s privileges. The target remains subject to its credentials, namespaces, LSM policy, and other kernel controls when a continued syscall executes. A supervisor that performs an operation itself, however, acts under the supervisor’s own authority unless it deliberately constrains that operation.
This creates a deputy problem. If a privileged supervisor accepts attacker-controlled arguments and performs resource access without a strict policy, the mediation layer can expose authority that the sandboxed task did not previously possess. The filter can be narrow while the supervisor implementation is broad.
A robust design therefore treats the supervisor as a privileged protocol endpoint. Inputs are untrusted, allowed operations are explicit, mutable arguments are handled with race-aware patterns, and transferred descriptors carry only the authority required for the requested operation.
The security boundary spans filter, listener, and supervisor
Seccomp user notification is strongest when its scope is stated precisely. The filter selects calls for mediation. The listener descriptor conveys decision authority. The notification identifier tracks a pending kernel request. The supervisor applies deployment policy, and any continuation or emulation determines where the final operation occurs.
None of these elements alone establishes a complete sandbox. A filter that delegates too broadly can expose a large supervisor interface. A correct filter paired with an over-privileged supervisor can create a confused-deputy path. A careful supervisor can still make an invalid decision if it assumes pointer arguments remain stable across a continuation boundary.
The mechanism is therefore best treated as a controlled delegation channel for selected syscall decisions. Its value comes from placing a kernel-enforced pause before specific operations while keeping the policy engine outside the constrained process. Its limitation is equally concrete: the pause does not freeze every object that influenced the request, so the surrounding architecture must bind decisions to stable kernel objects whenever mutable user-space state would make approval ambiguous.