QuantyKube

ADR-013 The runtime's syscalls sit behind one unsafe crate

All pages

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.