sigilOS 0.6.0 gains remote desktop: a Lumen desktop projected over the network, with full capability isolation per session. Each remote client receives a framebuffer region and can inject pointer and keyboard events — all through Cap<Display>, Cap<Input>, and Cap<NetConn>, none of which can be forged or escalated. This RFC gates the 0.6.0 sprint assignments for the whole fleet. (sigil-os#21)
Three capabilities, one session
Every remote desktop session in sigilOS is defined by exactly three capabilities held by the session process:
The session process holds all three and nothing else — it cannot elevate, cannot access another session's framebuffer, cannot forge events for another WM context. The broker mints the caps and hands them over; the broker's elevation token never enters the session process.
Session lifecycle
Cap<NetConn> via cap_net_accept (Kernel syscall 110).fb_overlay_request, syscall 103) → receives Cap<Display> scoped to that slot's region. Max 8 concurrent sessions.Cap<Input> scoped to the session's WM input queue entry.rdp_session.sg). Session loop runs: read Display → RFB-encode → write NetConn; read NetConn → RFB-decode → write Input.Wire protocol: RFB (VNC-compatible)
The wire format is RFB — the same protocol used by VNC clients, which means any VNC-compatible viewer (RealVNC, TigerVNC, Screens, Jump Desktop) can connect to a sigilOS remote desktop session without a custom client.
- Server → client: framebuffer updates (raw or ZRLE-compressed) sent at each
fb_fliptick or when the delta exceeds a threshold. - Client → server:
PointerEventandKeyEventmessages mapped toCap<Input>write calls. - Auth: security type
Nonefor LAN.VeNCrypt/TLS for WAN, gated onCap<TLSConn>(0.6.1).
Per-session isolation invariants
These invariants hold for every session, and are enforced by the capability system — not by runtime checks in the session code:
- Each
Cap<Display>is scoped to exactly one overlay slot. A session process that calls a Display read outside its slot gets a capability fault, not data from another session. - Each
Cap<Input>is scoped to the session's own input queue. A session process cannot write to another session's WM context. - The session process never holds the broker's elevation token. It cannot call
id_elevatesuccessfully even if the binary is compromised. - A crashing session releases all three caps via ref-count drop. Adjacent sessions are unaffected.
Fleet implementation order
This RFC gates the 0.6.0 sprint. The implementation proceeds in dependency order:
| Step | Owner | Deliverable |
|---|---|---|
| 1 | Kernel | cap_net_listen(port) → Cap<NetConn> (syscall 109) + cap_net_accept(listener) → Cap<NetConn> (syscall 110) |
| 2 | OS | rdp_session.sg — session loop with loopback-stubbed caps: Display read → RFB encode → NetConn write; NetConn read → RFB decode → Input write |
| 3 | Video | vid_rfb_encode(prev_fb, curr_fb, out_buf) → bytes — frame-diff encoder (ZRLE or raw) |
| 4 | All | Integration test: local loopback client → PASS screendump showing projected Lumen desktop |
Open questions
- Transport: QUIC vs TCP for
Cap<NetConn>— QUIC has better latency on lossy links; TCP is simpler for the 0.6.0 deadline. - Frame rate: tick-driven (every
fb_flip) vs delta-threshold (only when >N pixels changed) — delta-threshold reduces bandwidth but adds complexity. - Reconnect: stateless (client re-establishes) vs stateful (session survives a brief disconnect) — stateless first, stateful as 0.6.1 stretch.