How Linux Manages the Crosvm Virtual Machine Monitor
The crosvm virtual machine monitor, originally developed by Google for ChromeOS and the Android Virtualization Framework, is a user-space hypervisor written in Rust that runs guest operating systems securely. Linux manages crosvm by utilizing the Kernel-based Virtual Machine (KVM) API to handle hardware-accelerated CPU and memory virtualization, while relying on standard Linux scheduling, memory mappings, and sandboxing primitives to control crosvm's execution. By treating crosvm as a standard user-space process divided into strictly isolated threads and subprocesses, the host Linux kernel enforces resource boundaries, routes I/O events, and maintains system integrity.
Hardware Virtualization via the KVM Interface
Crosvm does not execute privileged CPU instructions directly.
Instead, Linux exposes hypervisor capabilities to crosvm through the
/dev/kvm character device. Crosvm opens this device node
and issues a series of ioctl system calls to manage the
guest lifecycle:
- VM Creation: Crosvm calls
KVM_CREATE_VMto initialize a virtual machine instance inside the Linux kernel. - Virtual CPU Execution: For every guest virtual CPU
(vCPU), crosvm creates a dedicated host thread that executes
KVM_CREATE_VCPU. The thread enters a loop callingKVM_RUN, signaling Linux to switch the CPU core from host context to guest context using hardware extensions (such as Intel VT-x or AMD-V). - Exit Handling: When the guest attempts an operation requiring hypervisor intervention—such as memory-mapped I/O (MMIO) or accessing specific control registers—the CPU generates a VM exit. The Linux KVM module catches this event and returns control to crosvm's vCPU thread in user space to emulate the required action.
Memory Allocation and Mapping
Linux manages guest physical memory by treating it as allocated user-space memory inside the crosvm process:
- Host Allocation: Crosvm allocates guest RAM using
the
mmapsystem call, creating a large, contiguous block of anonymous memory or shared memory (memfd_create). - KVM Slot Registration: Crosvm invokes
KVM_SET_USER_MEMORY_REGIONto inform the Linux kernel that a specific region of host virtual memory corresponds to the guest's physical address space. - Paging and EPT/NPT: The host kernel configures Extended Page Tables (EPT) or Nested Page Tables (NPT) to translate Guest Physical Addresses (GPA) to Host Physical Addresses (HPA). The Linux kernel's standard page allocator, transparent huge pages (THP), and swap mechanisms manage these pages just as they would for standard processes.
Scheduling and Process Concurrency
To the Linux Completely Fair Scheduler (CFS), crosvm's vCPUs appear as normal POSIX threads. This architectural choice yields several operational behaviors:
- vCPU Scheduling: The host kernel dynamically
schedules each vCPU thread across physical cores. If a guest vCPU
executes a
HLT(halt) instruction, KVM traps the call and puts the corresponding host thread to sleep until an interrupt arrives, freeing host CPU cycles. - Device Worker Threads: Virtio devices (such as virtio-net, virtio-block, and virtio-gpu) run on separate host threads or dedicated processes to prevent slow I/O operations from blocking vCPU execution.
Sandboxing and Security Isolation
A primary design goal of crosvm is security, achieved by combining Rust's memory safety guarantees with Linux containment features:
- Subprocess Isolation: Instead of hosting all device emulations within a single monolithic process, crosvm can fork separate processes for individual virtio devices.
- Namespaces: Linux namespaces (mount, user, PID, network) restrict the visibility of host resources so that compromised device emulators cannot view or modify the host filesystem or system state.
- Seccomp Filters: Crosvm compiles strict Secure Computing (seccomp) BPF filters for each thread and process. Linux immediately drops unneeded system calls, preventing compromised devices from issuing arbitrary kernel requests.
- Capabilities and File Descriptor Passing: Crosvm drops standard root capabilities, retaining only necessary access rights. Communication between isolated processes and the main VMM occurs strictly over UNIX domain sockets using explicit file descriptor passing.
I/O Signaling and Asynchronous Events
Communication between the Linux kernel, crosvm, and the guest relies on lightweight Linux IPC primitives:
- Eventfd and Irqfd: Crosvm uses Linux
eventfdhandles registered viaKVM_IRQFDto inject virtual interrupts directly into the guest from user space without full context switches. - Ioevents: Guest accesses to specific I/O addresses
trigger
KVM_IOEVENTFD, which automatically notifies crosvm via an eventfd. - Epoll Loops: Crosvm’s device loops monitor multiple
eventfds and network/storage file descriptors simultaneously using Linux
epoll, ensuring low-latency, non-blocking I/O multiplexing across all virtual devices.