How Microsandbox Handles Inter-Process Communication: 3 IPC Mechanisms Explained
Microsandbox implements three complementary inter-process communication (IPC) mechanisms—Virtio-vsock for guest-host communication, an Agent Relay for SDK client connections, and a Lifecycle Guard for exclusive sandbox ownership—that together enable secure, isolated communication between host processes, sandboxed guests, and SDK clients.
This article examines the IPC architecture in superradcompany/microsandbox, analyzing how the runtime enables communication across isolation boundaries while maintaining security guarantees.
Virtio-vsock: Guest-Host Communication
Microsandbox uses Virtio-vsock to expose host services to sandboxed guests through emulated vsock devices. This mechanism connects the guest's CID address space to host-side IPC endpoints.
Vsock Specification
The vsock configuration originates in the sandbox specification defined in packages/microsandbox-types/rust/lib/domain.rs:
pub struct VsockSpec {
/// One host local‑IPC endpoint exposed on a host‑CID vsock port.
pub routes: Vec<VsockRouteSpec>,
}
Each VsockRouteSpec defines a mapping between a host IPC endpoint and a guest-visible vsock port. The runtime supports both stream (TCP-like) and datagram (UDP-like) semantics.
Host-Side Back-Ends
During VM startup in crates/runtime/lib/vm.rs, vsock routes become concrete back-end implementations:
use microsandbox_vsock::{UnixDatagramPortBackend, UnixStreamPortBackend};
let vsock_backends = config.spec.vsock.routes.clone();
The back-end implementations handle platform-specific transport:
- Linux/macOS: Unix domain sockets (
UnixStreamPortBackend,UnixDatagramPortBackend) - Windows: Named pipes (equivalent abstractions in
crates/vsock/lib/stream.rsandcrates/vsock/lib/dgram.rs)
Guests connect using standard vsock APIs, unaware of the host's actual transport implementation.
Agent Relay: SDK Client to Guest Communication
The Agent Relay bridges SDK clients with the guest's internal agent (agentd). This local IPC mechanism enables programmatic control of sandboxed workloads.
Connection Establishment
The relay listens on per-sandbox sockets created in crates/runtime/lib/relay.rs:
// AgentListener::bind creates the socket with proper cleanup
let listener = AgentListener::bind(&socket_path).await?;
The implementation handles stale socket files and ensures parent directory creation at lines 49-66.
Client Isolation via Correlation IDs
Each connecting client receives an exclusive correlation-ID range to isolate protocol frames:
// Handshake assigns ID range to client
let mut handshake = Vec::with_capacity(8 + ready_frame.len());
handshake.extend_from_slice(&id_start.to_be_bytes());
handshake.extend_from_slice(&id_end_exclusive.to_be_bytes());
handshake.extend_from_slice(&ready_frame);
writer_half.write_all(&handshake).await?;
The slot allocation uses AGENT_RELAY_ID_RANGE_STEP to partition the 64-bit ID space, ensuring responses route to correct clients even with concurrent connections.
Frame Forwarding Architecture
The relay operates on raw binary frames without parsing overhead:
- TX path: Client →
tx_ring→ guest agent - RX path: Guest agent →
rx_ring→ client
Connection cleanup includes SIGKILL delivery to active exec sessions when clients disconnect, implemented in the session management logic.
Legacy Compatibility
The relay maintains backward compatibility through symbolic links:
publish_legacy_agent_link— canonicalagent.sockaccesspublish_legacy_control_link— legacycontrol.sockrouting
New clients use the unified socket layout while existing code continues functioning.
Lifecycle Guard: Exclusive Sandbox Ownership
The SandboxLifecycleGuard prevents race conditions when multiple host processes attempt to launch identical sandbox configurations.
Advisory Locking Implementation
In crates/runtime/lib/ipc.rs, the guard acquires an exclusive flock:
let file = OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(&path)?;
let operation = libc::LOCK_EX | if nonblocking { libc::LOCK_NB } else { 0 };
if unsafe { libc::flock(file.as_raw_fd(), operation) } == 0 {
Ok(Some(SandboxLifecycleGuard { file }))
}
Lock files reside at locks/<hash>.lock relative to the run directory.
Lock Persistence Across Processes
The guard supports duplication into sandbox child processes. This ensures the lock persists after the launcher exits, preventing premature sandbox termination due to lock release.
Using Microsandbox IPC in Practice
Rust SDK: Configuring Vsock Routes
use microsandbox_sdk::sandbox::SandboxBuilder;
let sandbox = SandboxBuilder::new()
.vsock("/run/host-api.sock", 5000) // Unix socket exposed on vsock port 5000
.vsock_dgram("/run/metrics.sock", 5001) // Datagram route
.build()
.await?;
The vsock and vsock_dgram methods in sdk/rust/lib/sandbox/builder.rs (lines 803-820) populate the VsockRouteSpec vector.
Python SDK: Connecting to Running Sandboxes
import microsandbox
sandbox = microsandbox.Sandbox(name="demo")
client = sandbox.connect() # Connects via agent.sock
result = client.exec("echo hello")
print(result.stdout)
Python arguments parse through sdk/python/src/helpers.rs before forwarding to the Rust builder. The connection routes through the Agent Relay.
Manual Socket Inspection
# Discover socket path
cat /tmp/msb/run/sandboxes/87eba76e7f3164534045ba92/agent.sock
# Raw binary communication
socat - UNIX-CONNECT:/tmp/msb/run/sandboxes/87eba76e7f3164534045ba92/agent.sock
Socket paths generate via sandbox_socket_paths in crates/runtime/lib/ipc.rs (lines 59-76), incorporating sandbox hashes for isolation.
Key Implementation Files
| Path | Responsibility |
|---|---|
crates/runtime/lib/ipc.rs |
Socket path generation, lifecycle lock acquisition, socket cleanup |
crates/runtime/lib/relay.rs |
AgentRelay implementation: handshakes, ID ranges, frame forwarding |
crates/vsock/lib/stream.rs |
Unix stream socket vsock back-end |
crates/vsock/lib/dgram.rs |
Unix datagram socket vsock back-end |
packages/microsandbox-types/rust/lib/domain.rs |
VsockSpec, VsockRouteSpec definitions |
sdk/rust/lib/sandbox/builder.rs |
Rust SDK vsock configuration methods |
sdk/python/src/helpers.rs |
Python SDK argument parsing |
sdk/node-ts/native/sandbox_builder.rs |
TypeScript/Node SDK bindings |
All IPC artifacts reside under the sandbox's run directory ($MSB_HOME/run), enabling complete cleanup on termination.
Summary
- Virtio-vsock provides guest-to-host connectivity through emulated devices backed by Unix sockets or named pipes, configured via
VsockRouteSpecentries - Agent Relay manages SDK client connections using correlation-ID isolation and raw frame forwarding over
agent.sock/control.sock - Lifecycle Guard ensures single-owner semantics through advisory file locking that survives process boundaries
- All three mechanisms compose to enable secure, isolated communication without sacrificing performance or compatibility
Frequently Asked Questions
How does microsandbox prevent multiple SDK clients from interfering with each other?
The Agent Relay assigns each client an exclusive correlation-ID range during the initial handshake. This range determines which protocol frames belong to which client, ensuring response isolation even with concurrent connections to the same sandbox.
Can vsock routes use different transport types on Linux versus Windows?
Yes. The VsockRouteSpec configuration is transport-agnostic; the runtime selects appropriate back-ends automatically. Linux and macOS use UnixStreamPortBackend or UnixDatagramPortBackend, while Windows uses equivalent named pipe implementations—guest code remains identical across platforms.
What happens if a client disconnects while running a command in the sandbox?
The Agent Relay detects connection loss and delivers SIGKILL to any active exec sessions associated with that client's correlation-ID range. This prevents orphaned processes and ensures resource cleanup.
Is the lifecycle guard required for all sandbox operations?
The guard is mandatory for sandbox launch operations to prevent duplicate initialization. The non-blocking flag (LOCK_NB) enables fast-fail when a sandbox is already running, while the duplicatable lock file descriptor allows the guard to persist across fork/exec boundaries.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →