Commit graph

93 commits

Author SHA1 Message Date
5962f97df6 Update wayland-proxy-virtwl with fractional scaling 2026-02-15 17:42:13 +00:00
7d90610d54 Strip unsafe attributes from guest .desktop files
Switch from blacklist to whitelist: only known-safe keys are preserved.
Fixes host data leaking into VM context menus (e.g. recent files via
Actions groups) and cross-VM window grouping (via StartupWMClass).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:53:02 +00:00
f300aa7e8e Allow most sample rates in guest pipewire 2026-02-15 16:36:51 +00:00
8ccd7868e7 More KDE patches for VM color identification
Decorations on task manager, alt-tab and thumbnails. If windows from multiple
VMs are grouped, the group is only colored if all windows match.
2026-02-15 15:58:35 +00:00
ba6d01488e feat(modules): initialize shared home from template directory
New VM home directories are created by copying /var/lib/vmsilo/home-template
on first start, allowing users to seed dotfiles and configs. The template
directory is created via tmpfiles and owned by the configured user.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:23:46 +00:00
ba0f77acf7 feat(modules): add per-VM sharedHome option for virtiofs home directory
Shares a host directory as /home/user in guest VMs via virtiofs, enabled
by default. Accepts true (/shared/<vmname>), a custom path string, or
false to disable. Host directory is created with correct uid:gid ownership
at VM start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 12:01:12 +00:00
d11ac67a02 Add KWin patch to draw borders on window icons 2026-02-15 02:23:57 +00:00
cbfab2fc6d feat(modules): add per-VM waylandProxy option (wayland-proxy-virtwl or sommelier)
Allows each VM to choose its Wayland proxy. Defaults to wayland-proxy-virtwl
(existing behavior). Setting waylandProxy = "sommelier" uses the ChromeOS
sommelier compositor instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 17:09:56 +00:00
9055ffe954 refactor(modules): change TAP naming from vm-<name><idx> to <name>-<idx>
Drop the vm- prefix, add dash separator between VM name and interface
index, and remove the 10-character VM name limit. Long names that would
exceed IFNAMSIZ (15 chars) are truncated with VM ID appended for
uniqueness (e.g., bankingsupe3-22 for id=3).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:32:37 +00:00
3dbe03ea8a fix(modules): guard tap submodule accesses against null
When type = "tap" but no tap sub-options are set, iface.tap is null.
Guard all iface.tap.* accesses so assertions fire cleanly instead of
crashing during evaluation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:16:22 +00:00
8f0eefe51c feat(modules): add tap.bridge option for bridged TAP interfaces
Allow TAP interfaces to be added to a named host bridge
(networking.bridges) instead of being assigned a host IP.
Only one of tap.hostAddress or tap.bridge may be set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:07:57 +00:00
cc9b8edd45 feat(net): make tap.hostAddress optional
Allow TAP interfaces without a host-side IP address. This supports
use cases like bridged networking where the host doesn't need an IP
on the TAP interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:59:14 +00:00
62ecea74a8 feat(net): rename TAP interfaces to vm-<name><ifIndex> for multi-tap support
TAP interfaces were named tap-<vmname>, which collides when a VM has
multiple TAP interfaces. Use vm-<vmname><ifIndex> instead, where ifIndex
is the PCI slot number (22-36). Add assertion that VM names are at most
10 characters to stay within the 15-char Linux interface name limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 15:57:18 +00:00
488e38873d fix(rootfs): move ephemeral qcow2 from /run to /var/lib/vmsilo
/run is tmpfs, so placing the ephemeral disk there defeats the purpose
of moving writes off RAM. Use /var/lib/vmsilo/ which is on real disk.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 13:55:34 +00:00
32d6a4a98f feat(rootfs): move overlay upper layer from tmpfs to ephemeral qcow2
VM root overlay writes now go to a sparse qcow2 disk instead of tmpfs,
reducing host RAM usage. The host creates the qcow2 at VM start and
deletes it at stop. The guest formats it as ext4 with discard support.

Adds rootOverlay option (type: qcow2/tmpfs, size: default 10G) with
tmpfs available as fallback for the original behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 12:58:02 +00:00
71c94949af fix(nix-module): update services.nix for attrset network.interfaces
Use lib.attrValues to convert interfaces attrset to list for
lib.concatMap and lib.any operations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 23:45:53 +00:00
7c53c7fbe6 fix(nix-module): update assertions for attrset network.interfaces
The assertions were still using list operations (lib.imap0, lib.length)
on vm.network.interfaces after it was changed to an attrset.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 23:44:03 +00:00
67e7a1b2c3 feat(nix-module): user-specified network interface names
Change network.interfaces from list to attrset where keys become
guest-visible interface names. Names are passed to the guest via
vmsilo.ifname=<name>,<mac> kernel parameters and applied at early
boot via udev rules.

- Add sortedInterfaceList helper for deterministic PCI slot assignment
- Update all interface iteration to use sorted attrset
- Add vmsilo-ifname-rules initrd service to generate udev rules
- MAC addresses now generated from vmName-userIfName hash

BREAKING: network.interfaces syntax changes from list to attrset:
  Before: interfaces = [{ type = "tap"; ... }];
  After:  interfaces = { wan = { type = "tap"; ... }; };

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 23:33:13 +00:00
d601b6b415 feat(nix-module): enrich VM config with interface names
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 22:52:06 +00:00
629be2313e feat(nix-module): allow guestConfig to be a function
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 22:51:40 +00:00
7ed1b1a930 refactor(nix-module): split config.nix into focused modules
Split the 1,409-line modules/config.nix into 9 focused modules:

- lib/helpers.nix: Pure utility functions (CIDR, MAC generation, PCI helpers)
- assertions.nix: All validation assertions
- pci.nix: PCI isolation (vfio-pci, udev rules, activation script)
- networking.nix: TAP interfaces, NAT, vm-switch activation
- services.nix: Systemd units (sockets, services, tmpfiles, polkit)
- scripts.nix: VM launcher and user scripts (vm-run, vm-start, etc.)
- desktop.nix: Desktop integration (.desktop files, bash completion)
- overlay.nix: KWin window decoration patches
- package.nix: Package assembly and environment config

Each module imports lib/helpers.nix for shared functions and computes
its own derived values from cfg, keeping modules independent.

Added internal options (_internal.vmScripts, proxyScripts, userScripts,
desktopFilesPackage, bashCompletionScript) for inter-module communication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 21:35:57 +00:00
4896f40f46 refactor(nix-module): extract helpers and add validation assertions
- Extract routeSubmodule type shared between routes/v6Routes (options.nix)
- Add isVmSwitchIface helper to unify interface type checking
- Rename isBdfGlobal to isBdf and remove duplicate local definition
- Add parseCIDR helper for consistent CIDR parsing across 4 locations
- Add resolveOptionalConfig helper for tri-state GPU/sound config
- Add assertions for tap.hostAddress and CIDR format validation
- Extract kernelParamHelper for /proc/cmdline parsing in guest scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 21:35:04 +00:00
29f05f92aa chore: remove dead code, fix MAC generation bug, update docs
Remove unused Rust code found by review: EthernetFrame struct,
extract_dest_mac(), MAX_FRAME_SIZE, MAX_TSO_FRAME, PacketForwarder.our_ip,
EgressBuffer.routes, and redundant serde_json dev-dependency.

Fix MAC generation to use interface name (e.g. enp0s22) instead of stale
idx+16 offset that diverged when PCI slot was changed to idx+22.

Fix README.md: wrong socket path, non-existent vmNetwork.router option
(now receiveBroadcast/routes), stale PCI offset examples, incomplete
vm-switch networking example. Add --quiet flag to CLI docs in both
README.md and CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 20:26:33 +00:00
e93749de58 feat(nix-module): add routes option to vmNetwork for per-peer subnet routing
Add vmNetwork.routes option (list of CIDR strings) that gets written
atomically to the vm-switch config directory. Enables declaring subnets
reachable through a VM for longest-prefix-match routing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 19:29:45 +00:00
26168e95b8 refactor: remove VmRole, unify config files to client.ip/client.mac
The router/client role distinction in vm-switch is no longer meaningful
with L3 IP-based forwarding. All VMs now use client.ip/client.mac/
client.sock uniformly; the only behavioral difference is the
receive_broadcast flag file.

- Remove VmRole enum and all role-based logic from Rust code
- Rename NixOS option vmNetwork.router to vmNetwork.receiveBroadcast
- Remove "exactly one router per network" assertion
- Update bufferbloat-test, documentation, and all tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 19:06:26 +00:00
3f049f41fe feat(nix-module): expose FQ-CoDel tunables in vm-switch options
Replace removed initialCredits with bufferSize and add fqCodelTarget,
fqCodelInterval, fqCodelLimit, fqCodelQuantum options.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 16:52:00 +00:00
dcb042c6f5 Fix KWin patch order 2026-02-13 16:51:58 +00:00
1f5acb64fa Update KWin patches to draw borders on popup windows 2026-02-13 16:47:40 +00:00
cc2c3c2e08 feat(modules): generate IP config files for vm-switch L3
Activation script now writes:
  <vm>/<role>.ip - IPv4 address from interface config
  <vm>/<role>.mac - MAC address
  <vm>/receive_broadcast - flag for router VMs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 17:58:36 +00:00
ac90bb5b06 Fix PCI address formatting to use hexadecimal
PCI addresses use hex notation (00:16.0, 00:1a.0) but the code was
outputting decimal. Also start at slot 0x16 (22 decimal) to leave
more room for crosvm auto-assigned devices.

- Use lib.toHexString for PCI address generation
- Change base offset from 16 to 22
- Replace hardcoded values with helper function calls
- Update CLAUDE.md documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 23:21:55 +00:00
cedca60b5d docs: Add L3 forwarding design for vm-switch
Design for changing vm-switch from L2 (MAC-based) to L3 (IP-based)
forwarding. Key changes:
- Forward packets based on destination IP instead of MAC
- ARP proxy responds with real peer MACs
- ACL via peers/ directory (structural enforcement)
- Anti-spoofing via source IP validation on ingress
- Broadcast limited to 255.255.255.255

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 23:07:58 +00:00
be129974d4 Remove unsupported mac param from vhost-user net args
crosvm's --vhost-user type=net doesn't accept a mac parameter;
the MAC address is provided by the vhost-user backend (vm-switch).

Also fix pci-device -> pci-address parameter name.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 22:40:03 +00:00
2656d4ef3a Fix error in interface configuration code
Also remove plan
2026-02-11 22:02:42 +00:00
87c3a449f6 Unify VM network configuration into single network option
Replace fragmented hostNetworking (boolean) and vmNetwork (attrsOf) with
a unified network option containing nameservers and an interfaces list.
Each interface specifies type (tap/vm-switch), addressing, and routing.

Key changes:
- PCI-based interface naming (ifIndex = position + 16) for predictable
  names like enp0s16, enp0s17
- MAC generation now based on SHA1("${vmName}-${ifIndex}")
- Kernel param systemd.hostname= replaces custom vmsilo.hostname=
- Remove net.ifnames=0 and set-hostname service (systemd handles both)
- Enable predictable interface names in guest
- Add assertions for interface validation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 21:47:04 +00:00
30c4c105d8 Use systemd-network-generator for VM network configuration
Replace the imperative configure-network service with systemd's built-in
network generator. This parses ip=, rd.route=, and nameserver= kernel
parameters and generates .network files that networkd manages natively.

Benefits:
- network-online.target now waits correctly for network configuration
- Consistent with NixOS/systemd patterns
- Removes imperative shell script
- Adds nameserver configuration support

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 19:35:40 +00:00
89e24d964d modules: Search system icon themes for VM desktop icons
Previously, icon copying only searched within each application package's
own icons. Apps like konsole that use icons from system themes (breeze)
would have missing icons in the VM desktop menu.

Now searches breeze-icons and hicolor-icon-theme as fallback after
package-bundled icons, ensuring icons are found and copied with the
VM-prefixed name regardless of their source.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:46:02 +00:00
056615db8d vm-switch: Add --initial-credits option, replace --buffer-size
The user-facing parameter is now the initial credit budget (how many
bytes can be in-flight before backpressure pauses TX), not the raw
ring capacity. Capacity is derived: initial_credits + CREDIT_HEADROOM.

Export CREDIT_HEADROOM constant from ring.rs (requires entry_size to
be const fn). Default --initial-credits is 128k, giving ~259k capacity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:37:32 +00:00
e68e6cbccf vm-switch: Fix credit headroom to account for wrap-around sentinel waste
When push() wraps around, it costs entry_size + sentinel_waste (up to
2x the frame size). With only 1x headroom, push() could fail despite
positive credits when free space was split across the wrap point.

Double the headroom reservation to 2 * entry_size(MAX_TSO_FRAME) and
increase the default --buffer-size from 128k to 256k so initial credits
remain usable (~131KB with the new headroom).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 12:23:48 +00:00
825a611420 vm-switch: Add --buffer-size option for configurable ring buffer capacity
The ring buffer data region is allocated at a fixed 512 KiB but the new
--buffer-size flag limits how much of it may be used (default 128 KiB).
Accepts plain bytes ("65536") or k/K suffix ("128k"). This lets operators
tune memory vs. burst-absorption per peer without changing the underlying
shared-memory layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 01:27:35 +00:00
6f398c9e59 vm-switch: Name worker processes for visibility in ps/top
Worker processes now set their title to "vm-switch(<network>): <vm>"
by overwriting the argv buffer and setting prctl(PR_SET_NAME). Add
-n/--name CLI option to specify the network name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 18:16:28 +00:00
6496d1ad62 Add dependsOn VM option to trigger starting other VMs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 17:28:51 +00:00
a71f7d14d2 Quote --shared-dir args to fix uidmap with space-separated values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 22:45:52 +00:00
f203426a9e Rename disposable/idleTimeout to autoShutdown.enable/after, add autoStart option
autoShutdown is a submodule with enable (bool) and after (int seconds).
autoStart (bool) adds wantedBy multi-user.target to boot VM automatically.
Kernel parameters renamed to match: autoShutdown.enable, autoShutdown.after.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 22:39:05 +00:00
8ea84378c5 Rename project from qubes-lite to vmsilo
All references updated: NixOS module namespace (programs.vmsilo),
systemd units (vmsilo-*), runtime paths (/run/vmsilo/), bash
completion functions (_vmsilo_*), XDG categories (X-Vmsilo-*),
desktop integration, and documentation. No backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 20:34:39 +00:00
6941d2fe4c feat(vm-switch): add process isolation with namespace sandbox and seccomp
Replace the thread-based vhost-user backend architecture with a
fork-based process model where each VM gets its own child process.
This enables strong isolation between VMs handling untrusted network
traffic, with multiple layers of defense in depth.

Process model:
- Main process watches config directory and orchestrates child lifecycle
- One child process forked per VM, running as vhost-user net backend
- Children communicate via SOCK_SEQPACKET control channel with SCM_RIGHTS
- Automatic child restart on crash/disconnect, with peer notification
- Ping/pong heartbeat monitoring for worker health (1s interval, 100ms timeout)
- SIGCHLD handling integrated into tokio event loop

Inter-process packet forwarding:
- Lock-free SPSC ring buffers in shared memory (memfd + mmap)
- 64-slot rings (~598KB each) with atomic head/tail, no locks in datapath
- Eventfd signaling for empty-to-non-empty transitions
- Main orchestrates buffer exchange: GetBuffer -> BufferReady -> PutBuffer
- Zero-copy path: producers write directly into consumer's shared memory

Namespace sandbox (applied before tokio, single-threaded):
- User namespace: unprivileged outside, UID 0 inside
- PID namespace: main is PID 1, children invisible to host
- Mount namespace: minimal tmpfs root with /config, /dev, /proc, /tmp
- IPC namespace: isolated System V IPC
- Network namespace: empty, communication only via inherited FDs
- Controllable via --no-sandbox flag

Seccomp BPF filtering (two-tier whitelist):
- Main filter: allows fork, socket creation, inotify, openat
- Child filter: strict subset - no fork, no socket, no file open
- Child filter applied after vhost setup, before event loop
- Modes: kill (default), trap (SIGSYS debug), log, disabled

Also adds vm-switch service dependencies to VM units in the NixOS
module so VMs wait for their network switch before starting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 20:19:26 +00:00
6722c0fbb4 Patch KDE to force serverside decoraations and full window frame 2026-02-09 17:16:34 +00:00
ddbf16133e Add VM color option for window decoration styling
Pass color via wayland security context app_id (vmsilo:<name>:<color>)
so kwin can style window decorations per-VM.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 00:04:30 +00:00
29d4464a90 Add kwin patch for VM decoration colors via security context
Override kwin when qubes-lite is enabled to apply kde-decoration.patch,
which colors window decorations based on vmsilo:<vmname>:<color> security
context from wayland-proxy-virtwl.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 23:43:27 +00:00
9f6d87a606 Fix vm-shell bash completion for options
Add completion for --ssh and --root options, and ensure VM name
completion works after options are specified.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 22:07:14 +00:00
df39f26b11 Prepend VM name to desktop entry names
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 21:52:43 +00:00