ADR-013, from docs/DECISIONS.md in the QuantyKube repository.
Status In force
The node runtime (ADR-005) needs namespaces, mounts, pivot_root and a
clone into new namespaces, none of which the standard library wraps. They
are declared by hand against glibc in crates/quantykube-sys, and that
crate holds every unsafe block in QuantyKube. This is QuantyDB's answer
to the same question (its ADR-023): unsafe at one small boundary where no
safe way exists, never as a shortcut.
The one rule the crate exists to keep: between the clone and the exec, the child only makes syscalls on memory prepared before the clone. It does not allocate, lock or print, because another thread of the parent may have held a lock at the moment of the clone, and the child's copy of that lock would never be released. Failures are reported as the child's exit status, one number per setup step.
quantykube sandbox exposes it for measuring against runc, with what
runc's default configuration does (docs/RUNTIME.md), the seccomp filter
built by hand as BPF: wrong architecture and the x32 ABI kill, clone
with namespace flags and 47 dangerous calls get EPERM, and clone3 gets
ENOSYS so libc falls back to clone, whose flags a filter can see. The
child waits on a pipe until the parent has put it into its cgroup, so
none of its own code runs outside the limits. It is not a runtime yet:
no CRI and no image store.
ADR-024 replaced the 47 calls with Docker's allowlist.
The cost: a crate of code the compiler cannot check, written against one libc and one architecture, x86_64 Linux, until a second one is needed.