Secure Containers Set 11 — seccomp notification + SELinux mount labels
Set 11 extends the guest security layer delivered in Set 10. It adds a bounded
in-guest supervisor for explicit seccomp user-notification rules, applies OCI
linux.mountLabel to OCI-created mounts, and exposes aggregate security
counters through the container-agent lifecycle protocol.
This is an additive delta over Set 10. When replaying onto the current FluxVM
main, retain the newer namespace/Sentinel work already upstream and replay the
Set 11 guest-security changes rather than replacing those files wholesale.
Seccomp user notification
Explicit syscall rules using SCMP_ACT_NOTIFY are now accepted. The listener
fd created by libseccomp is transferred with SCM_RIGHTS over a private Unix
socketpair to a supervisor thread that stays in the guest container-agent
process, outside the workload's chroot and seccomp filter. The supervisor uses
libseccomp's notification API to receive, validate, and respond to requests.
The default policy is fail closed:
io.zyvor.seccomp.notify.mode=deny(default) returnsEPERM.io.zyvor.seccomp.notify.errno=<1..4095>changes the denial errno.io.zyvor.seccomp.notify.mode=continueexplicitly opts intoSECCOMP_USER_NOTIF_FLAG_CONTINUE.
continue must be treated as a privileged policy choice. The kernel resumes the
original syscall after the supervisor replies and path/fd arguments can change
between inspection and execution; Set 11 deliberately does not claim that
CONTINUE provides a TOCTOU-safe syscall emulation boundary. No syscall argument
values are exported in the audit line.
io.zyvor.seccomp.notify.mode=addfd (S9) enables SECCOMP_IOCTL_NOTIF_ADDFD:
the supervisor injects io.zyvor.seccomp.notify.addfd-src into the notify
target and returns the installed fd number as the syscall result.
io.zyvor.seccomp.notify.mode=remote asks the host for each decision over
AF_VSOCK (DEFAULT_SECCOMP_POLICY_PORT / io.zyvor.seccomp.notify.rpc-port).
The shim listens on the host; FLUXVM_SECCOMP_POLICY_RPC=continue|deny (default
deny) or FLUXVM_SECCOMP_POLICY_RPC_URL (HTTP POST) selects the broker. Timeouts
and errors fail closed. Syscall argument values are never sent on the wire.
addfd stays local-only (needs a supervisor fd in the guest).
Guest requirements for this feature are kernel seccomp user notification
(kernel 5.0+) and a libseccomp.so.2 exposing the v2.5-era notification API.
Use scripts/preflight-secure-containers-set11.sh inside the guest image before
enabling NOTIFY profiles.
SELinux linux.mountLabel
When OCI linux.mountLabel is present, Set 11 validates that SELinux is enabled
and libselinux.so.1 is available, then appends the standard
context="<label>" option to each OCI-created mount. Existing SELinux context
options (context, fscontext, defcontext, or rootcontext) conflict with a
separate mountLabel and are rejected rather than merged ambiguously. Invalid
control characters and mount-option escaping characters fail closed.
The support boundary is intentionally precise: the label is applied to mounts
created by the guest OCI setup path. The Pod rootfs arrives through the existing
virtiofs staging design before OCI mount setup, so Set 11 does not claim to
retroactively relabel that already-mounted virtiofs superblock. Process
selinuxLabel remains Set 10 behavior.
Security observability
The lifecycle protocol adds SecurityStats, returning VM-local cumulative
counters for:
- seccomp notifications received;
- notifications denied;
- notifications continued;
- broker errors;
- successfully created OCI mounts carrying
mountLabel; - agent-side LSM preflight failures.
The shim logs a snapshot when an init container/task is deleted. The
lsm_apply_failures counter is intentionally described as an agent/preflight
counter: failures that occur only in a forked child after copy-on-write cannot
be reliably reflected in the parent's in-memory counter. Container creation
still fails closed in those cases.
Validation gates
Host-independent validation in the release bundle covers protocol round-trips, NOTIFY policy parsing, bootstrap-deadlock rejection, mount-label formatting, shell/TOML/YAML parsing, Rust lexical checks, seccomp notification C ABI sizes, patch replay, byte comparison, manifest verification, and ZIP integrity.
The real-node gate must still validate:
- A guest with a NOTIFY profile receives the event and returns the configured denial errno without hanging.
- Explicit
continueresumes the syscall and increments the continued counter. - Killing the notified process/container does not leave the broker blocked or leak listener fds.
- A valid SELinux mount label is visible on a supported OCI-created tmpfs or bind mount in an enforcing guest.
- Invalid/unloaded LSM state fails container creation.
- Set 10 seccomp argument filters and device-cgroup BPF still pass unchanged.
- Existing Set 8/9 raw-block/VFIO and Set 6 namespace/Sentinel behavior remain
intact after rebase onto current
main.
This packaging environment does not have Rust, KVM, containerd, Kubernetes, libseccomp development headers, or an SELinux-enabled guest, so those live runtime gates are not claimed here.