The optimizations in ede53078b6 introduced a
but where the per-mime-type buffer size limit became a total size limit. This
commit fixes it to again apply per mime type, and also bumps the limit to
128MB.
writeShellScript doesn't set PATH, so head and grep were not found
in the sandboxed service (TemporaryFileSystem=/).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The readiness probe was sending a binary struct.pack message instead of
the ASCII proxy protocol (CONNECT <port>\n → OK <remoteport>\n), causing
it to always time out. Replace with a socat-based probe matching the
protocol used everywhere else.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set HOME, LIBGL_DRIVERS_PATH, __EGL_VENDOR_LIBRARY_DIRS, and add
/run/opengl-driver/lib to LD_LIBRARY_PATH so mesa can find DRI
drivers and EGL vendors. Set HOME to the per-VM GPU runtime dir
to fix shader cache directory creation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cloud-hypervisor's hybrid vsock (Unix socket + CONNECT protocol) doesn't
support half-close. When recv_pkt() gets a 0-byte read from shutdown(SHUT_WR),
it sends VSOCK_OP_SHUTDOWN with both RCV|SEND flags, tearing down the entire
connection and killing the response path.
Two fixes:
- Remove s.shutdown(SHUT_WR) from the vsock proxy
- Make guest command handler self-terminating: head -1 | bash. The pipe
gives bash a clean EOF after one command line, so it no longer depends
on vsock half-close to exit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove vmsilo-start-* user-facing symlinks from package.nix (internal
VM launcher scripts are only used by systemd ExecStart, not by users)
- Rename vmsilo-usb to vm-usb to match the vm-* naming convention
- Increase socat -t timeout in vm-run from default 0.5s to 5s to fix
missing output from console commands (cloud-hypervisor proxy startup
latency exceeded the default timeout window)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace crosvm xhci-based USB passthrough with usbip-rs over vsock,
enabling USB passthrough for both crosvm and cloud-hypervisor VMs.
Guest runs a persistent usbip-rs client listener on vsock port 5002.
Host runs one sandboxed usbip-rs host connect process per attached
device as a systemd template service (vmsilo-<vm>-usb@<devpath>).
Eliminates the JSON state file, file locking, and crosvm-specific
shell helper library in favor of systemd as the source of truth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the dual mkSocketWaitScript/socketWaitScript pair in vm-config.nix
with a single socketWaitScript taking an onTimeout argument. Add section
headers to scripts.nix to distinguish VM launcher scripts from proxy and
user-facing scripts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move usbHelperLib (~200 lines) and vmsiloUsbScript (~170 lines) from
scripts.nix into a dedicated usb.nix module. Deduplicate the
cloud-hypervisor USB rejection check into a shared usb_reject_ch_vm()
shell function. USB systemd services in services.nix continue consuming
cfg._internal.usbHelperLib unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The _generatedGuestConfig option was declared and read but never set by
any module, making it always evaluate to []. Remove the declaration and
simplify getEffectiveGuestConfig to read only from netvmInjections.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
chown the vsock socket to the configured user after VM creation so the
dbus-proxy (which runs as the user) can connect to it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 4: Break the monolithic systemd.services expression into named
generator functions (mkPrepServices, mkVmServices, mkProxyServices,
mkConsoleRelayServices, mkConsoleScreenServices, mkVirtiofsdServices,
mkSoundServices, mkDbusProxyServices, mkWaylandSeccontextServices,
mkGpuServices, mkUsbServices, mkBalloondService). The top-level
expression is now a clean concatenation of named generators.
Phase 5: Remove unused vm.tray option (superseded by vm.dbus.tray).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 2: Move getEffectiveInterfaces, getEffectiveIfaceMac, and
resolveColor into lib/helpers.nix so they're defined once instead of
copy-pasted across services.nix, networking.nix, assertions.nix, and
vm-config.nix. getEffectiveInterfaces takes netvmInjections as a
parameter to avoid the config-access issue.
Phase 3: Extract gpuSyscallAllowlist and soundSyscallAllowlist (~210
lines) from services.nix into lib/syscall-allowlists.nix.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deduplicate the computation shared between mkCrosvmVmScript and
mkCloudHypervisorVmScript by extracting it into a hypervisor-neutral
mkVmConfig function. Both script generators now consume this shared
attrset and only contain hypervisor-specific rendering logic.
Eliminates ~550 net lines from scripts.nix: rootfs resolution, GPU
normalization, kernel params, network entries, PCI handling, IOMMU
validation, and socket wait loops are now computed once.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The EnvFilter targeted `vmsilo_tray` (a stale name) instead of
`vmsilo_dbus_proxy`, causing all log output to be silently dropped.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
INFO for listening socket, initiating connection, and accepting
connection (with protocol/port/address fields). DEBUG for tray entry
and notification creation. TRACE for all vsock messages sent/received
with full contents.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- BalloonBackend trait abstracting over hypervisor-specific balloon control
- CrosvmBackend wrapping existing crosvm control socket protocol
- CloudHypervisorBackend using raw HTTP/1.1 over persistent Unix socket
(GET /api/v1/vm.balloon-statistics, PUT /api/v1/vm.resize)
- Watcher recognizes both crosvm-control.socket and
cloud-hypervisor-control.socket for auto-discovery
- dbus-proxy: CONNECT protocol support for cloud-hypervisor vsock,
generic stream handling, --cid/--vsock-socket CLI args
- NixOS module: enable dbus-proxy for all VMs, vary args by hypervisor
screen -dmS forks to background (daemon mode), which should work
without a controlling terminal. Type=forking tells systemd to expect
the fork.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
screen requires a controlling terminal which systemd services don't
provide. tmux works without a terminal via new-session without -d.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
screen requires a controlling terminal which systemd services don't
have. Using script(1) to allocate a pseudo-terminal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a vmsilo-<name>-console-screen systemd service for every VM that
attaches a GNU Screen session to the console PTY
(/run/vmsilo/<name>/console). The service polls for the PTY (needed for
cloud-hypervisor VMs), keeps the serial buffer drained, and cleans up
stale screen sessions on start and stop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cloud-hypervisor VMs now use PTY-direct serial mode and no longer need
a console-relay service. Filter the relay to crosvm VMs only via
lib.filter, removing the isCh/chRelayScript conditional logic. Also
add ExecStopPost cleanup of the console symlink for CH VMs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The root overlay disk had no serial set and the kernel param hardcoded
"raw,vdb" instead of "raw,ephemeral", so the guest couldn't find the
overlay disk by /dev/disk/by-id/virtio-ephemeral.
Also fixes: missing netvmInjections nameservers, shared dir mount params
only handling sharedHome (not all dirs with mountPath), additional disks
dropping id field, ephemeral disk using direct=false (double-caching),
missing IOMMU group validation for PCI passthrough, and redundant
ephemeral disk creation in the script body.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PipeWire's mempool allocator (mem.c) calls ftruncate() to size memfds
for shared memory. The missing syscall caused EPERM, which cascaded
through the adapter factory to produce EINVAL on pw_stream_connect.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Point PIPEWIRE_CONFIG_DIR at the pipewire package's data dir so
libpipewire finds client.conf directly, bypassing the /etc/pipewire
search path which doesn't have client.conf in the confinement.
Also fix sound.logLevel: RUST_LOG was being set unconditionally
(producing "RUST_LOG=" when null); now only set when logLevel is
configured.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The /etc/pipewire directory contains symlinks to the
pipewire-extra-config store path, which isn't in the confinement
closure. Add the pipewire config source to confinement.packages so
its full closure is available in the namespace.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set RUST_BACKTRACE=full on VM, GPU, sound, dbus-proxy, balloond, and
wayland-seccontext services for better crash diagnostics. Add per-VM
sound.logLevel option (default "info") that sets RUST_LOG on the
vhost-device-sound service.
Also document previously undocumented options in README: cloud-hypervisor
hugepages, netvmRange, sound.logLevel, sound.seccompPolicy,
cloudHypervisor.hugepages, cloudHypervisor.seccompPolicy.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mount the NixOS-generated pipewire config directory at /etc/pipewire
inside the confined sound service namespace — libpipewire has
/etc/pipewire as a compiled-in config search path.
Also add RUST_BACKTRACE=full to all Rust service environments
(balloond, VM, sound, dbus-proxy, wayland-seccontext, GPU) and a
sound.logLevel option for RUST_LOG control.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The confined vhost-device-sound service can't find client.conf because
the pipewire config files (in the default output) aren't in the
confinement closure — only the library output is pulled in transitively.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GPU, sound, and virtiofs backend services use Type=simple, so systemd
considers them started before they create their sockets. This race
causes crosvm to fail with "No such file or directory" on the
vhost-user socket paths. Add socket-wait loops (up to 30s) in both
crosvm and cloud-hypervisor start scripts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These syscalls were being denied in enforcing mode, causing GPU device
units to fail.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>