Protocols

Warden Driver Protocol

Separate workload fd 3 and fd 4 from the private host-driver control channel and guest protocols.

This document distinguishes the three descriptor spaces involved in a Warden execution. A descriptor number has meaning only inside one process. File descriptor 4 in a host driver and file descriptor 4 in a workload are not the same channel and do not share an ownership contract.

Three descriptor spaces

The native workload conventions are conditional:

Descriptor in the workloadPresent whenContract
0, 1, 2according to the selected I/O modeordinary stdio or diagnostics
3MAELYS_EXEC_IO_ISOLATED_DUPLEXapplication bytes; Warden does not interpret them
4MAELYS_EXECUTOR_NETWORK_EXTERNAL_CHANNELconnected Unix datagram control channel to the Egress adapter

With captured stdio there is no application fd 3. With network:none, direct networking or mediated proxy networking there is no workload network fd 4. These numbers are conventions for the workload child, not global reserved numbers that every Warden-related process must use the same way.

For example, Warden can create one socket pair and duplicate one end to fd 4 in an Apple driver. In a separate native execution it can create another, unrelated socket pair and duplicate one end to fd 4 in a workload. Each process has its own descriptor table, so no collision exists.

Outer driver protocol

The common host-driver envelope is Maelys Warden Driver Protocol / 1 (MWDP/1), frozen in 0.20.0. K0 migrated the operational Apple driver and the C backend from the former MWAC/1 magic to this framing, with no compatibility alias: a legacy driver still announcing MWAC/1 or MWAC-PROBE/2 fails closed during discovery. Both shipped host drivers speak it:

CODE
Warden core
    |
    | MWDP/1, AF_UNIX SOCK_STREAM
    | driver-private fd 4
    |
    +-- maelys-warden-apple-container-driver
    |
    `-- maelys-warden-krun-driver

Its common lifecycle envelope is:

CODE
HELLO -> HELLO_OK -> LAUNCH -> READY -> (SIGNAL | STOP)* -> EXIT
                                  \-----------------------> ERROR
SIGNAL and STOP receive an ACK before a later terminal EXIT when applicable.

READY is candidate-specific admission evidence. For a simple Krun launch it follows successful workload execve(). For krun-bubblewrap it follows the successful preflight and exec of the trusted Bubblewrap layer; failure to exec the image workload is then represented by the correlated, nonzero terminal Bubblewrap EXIT (currently 1 for the pinned helper), never by a fabricated workload outcome.

Controller request identifiers are nonzero and strictly increasing. A direct response repeats its request identifier, while terminal EXIT repeats the identifier of LAUNCH. The shared state machine rejects mismatched responses, duplicate or reordered requests and an EXIT unrelated to the admitted run.

The fixed fd is a bootstrap convention inside the driver process. The protocol is defined by its socket type, framing, state machine and ownership, not by an assumption that descriptor number 4 means the same thing elsewhere.

Release 0.19.0 still used the Apple-specific MWAC/1 magic. Release 0.20.0 replaced it with MWDP/1, a backend-neutral C codec and a role-aware state machine, and the frame protocol has been frozen since. Golden frames, malformed length, fragmented/coalesced stream reads, timeout, duplicate/out-of-order transition and a complete fake-Krun lifecycle are test gates. K2 has moved the production Krun executable to the same private --control-fd 4 contract and removed its diagnostic workload CLI. Its ABI backend consumes the sealed OCI launch artifact delivered by K4. Backend launch payloads stay versioned independently of MWDP/1: Krun payload 5 added an explicit inner_bubblewrap bit and a bounded recursive READ/WRITE rule table for K6 in 0.23.0; payload 6 added the optional, identity-pinned Egress AF_UNIX bridge and its bounded guest relay parameters for K7 in 0.24.0; payload 8 bound K9's explicit guest RUN admission and three private stdio vsock streams. Krun payload 9, livré en 0.33.0, ajoute l'identité complète du noyau brut Warden commun ; le driver la revalide puis appelle krun_set_kernel(..., KRUN_KERNEL_FORMAT_RAW, ...) avant le démarrage. Krun payload 10 and Containerization launch payload 2 carried the ABI 9 root mode plus the exact scratch ceiling. In 0.38.0, Krun payload 11 and direct Containerization payload 3 added the sealed ABI 10 execution budget and exact driver resource application. Containerization payload 4 adds the direct composite selector and resolved recursive filesystem rules; the Swift driver forwards them to MI/6 and never compiles Bubblewrap argv itself. The Apple Container service driver carries the same sealed budget in its independent payload 6. Its protected composite uses exact service VM sizing plus a Warden-owned nested cgroup and returns MWAR/2; the simple candidate remains ineligible. The Krun driver maps that listener to the fixed guest AF_VSOCK port 4520; it never receives policy destinations or credentials. Unsupported shapes fail before VM creation.

Depuis 0.38.0, les drivers Krun et Containerization direct exigent MI/6. Le SPEC contient le SHA-256 du rootfs attendu ; maelys-init relit le périphérique bloc, refuse toute différence, puis renvoie la mesure dans READY. EXIT ajoute trois compteurs non négatifs (user_usec, system_usec, maxrss_kib), la taille de scratch réellement appliquée, le mode racine et le résultat de cleanup. Ces compteurs proviennent du wait4 du fils workload direct. Ils couvrent son sous-arbre tel que le noyau le comptabilise au reap — le sous-arbre Bubblewrap pour un composite — mais pas les orphelins ensuite adoptés et reapés séparément par PID 1. Ils constituent un diagnostic d'exécution, jamais une comptabilité exhaustive de la VM, une base de facturation ou une limite de ressources. Les drivers les transportent dans le payload MWDP EXIT de 128 octets, qui ajoute les observations cgroup, le dépassement de deadline et la preuve de cleanup. Le seam commun accepte encore le payload historique de 8 octets du driver Apple service, sans lui attribuer ces garanties.

Inner guest control is backend-specific

The common driver protocol stops at the host driver boundary:

Apple Container does not currently boot maelys-init. Its driver requests Apple Container's useInit; the Apple service and vminitd supervise the guest container. The optional maelys-guest-supervisor is its Warden-owned entrypoint wrapper, not PID 1: it can supervise only, or additionally run the Egress relay, and owns the nested workload cgroup plus MWAR/2 observation.

Krun and the direct Containerization candidate boot Warden's lower-level Linux root and therefore share maelys-init plus MI/6. The Apple Container service candidate does not. MI/6 crosses the host/guest kernel boundary and remains separate from MWDP/1; it is not forced onto vminitd. maelys-init is one statically linked ELF: its private libmaelys-guest.a implementation separates PID-1 bootstrap from workload execution without introducing another guest process or protocol. See guest-runtime.md. Both guest entry points link the private libmaelys-guest-isolation.a, which owns canonical Bubblewrap argv construction and bounded preflight without making either lifecycle model depend on the other.