vmm-sys-util

Safe Rust wrappers around low-level Linux syscalls for building virtual machine monitors

Library
Cargo
v0.15.0
89stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
40/100Fair
Development Activity16
Maintenance20
Community52
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture78
Code Quality82
Innovation68
Learning Curve70

vmm-sys-util is a Rust crate maintained by the rust-vmm project that collects safe, ergonomic wrappers around the raw Linux system calls a virtual machine monitor (VMM) needs day to day: eventfd, epoll, timerfd, ioctl, signal handling, POSIX AIO, temp files, and more. Instead of every VMM reimplementing unsafe libc calls and error handling for the same handful of syscalls, this crate centralizes them behind typed, Result-returning APIs.

It is a foundational dependency across the rust-vmm ecosystem — used by projects like Firecracker, Cloud Hypervisor, and crosvm-adjacent tooling — because it turns error-prone unsafe FFI calls into small, well-tested, safe building blocks that any VMM component can depend on without duplicating the same low-level plumbing.

What You Get

  • EventFd, epoll (Epoll, EventSet, EpollEvent), and TimerFd wrappers for building non-blocking, event-driven I/O loops
  • ioctl_expr/ioctl_iow_nr!-style macros and helpers for constructing and issuing correctly-encoded ioctl calls, essential for talking to /dev/kvm and other device nodes
  • FamStructWrapper<T>, a safe wrapper for C flexible-array-member structs (the pattern KVM’s API relies on for variable-length ioctl payloads)
  • Signal-handling utilities (register_signal_handler) for installing safe Rust signal handlers over raw POSIX signal APIs
  • TempFile and TempDir types that auto-clean on drop, plus AsyncIoContext (POSIX AIO), SyscallReturnCode for uniform errno-to-io::Result conversion, Terminal raw-mode helpers, and Unix socket control-message (sock_ctrl_msg) support

Common Use Cases

  • Wiring a VMM’s vCPU thread to KVM_RUN exits using EventFd/epoll instead of hand-rolled raw syscalls
  • Issuing device-model ioctls (e.g. against /dev/kvm, /dev/vhost-vsock) with correctly computed ioctl numbers via the ioctl module
  • Decoding variable-length KVM ioctl structures (like kvm_cpuid2 or kvm_msr_list) safely using FamStructWrapper
  • Installing signal handlers for graceful VMM shutdown or vCPU thread interruption without writing raw sigaction FFI
  • Creating scoped temporary files/directories for snapshot or disk-image staging that clean themselves up automatically

Under The Hood

Architecture vmm-sys-util is organized as a flat collection of single-purpose modules rather than a layered framework: platform-gated modules live under src/linux/ (eventfd, epoll, timerfd, ioctl, signal, aio, poll, fallocate, seek_hole, write_zeroes) and src/unix/ (event, file_traits, sock_ctrl_msg, tempdir, terminal), re-exported flat at the crate root via pub use crate::linux::* / pub use crate::unix::* in src/lib.rs, gated behind #[cfg(any(target_os = "linux", target_os = "android"))] and #[cfg(unix)] respectively. Cross-platform helpers (align, errno, fam, metric, rand, syscall, tempfile) sit at the top level ungated. Each module wraps one syscall family end to end — e.g. linux/eventfd.rs wraps libc::eventfd inside a File-backed EventFd struct implementing AsRawFd/FromRawFd, and syscall.rs’s generic SyscallReturnCode<T> centralizes the common ‘-1 means check errno’ pattern that nearly every wrapper reuses via .into_result(). There is no central runtime or registry; consumers import exactly the modules they need.

Tech Stack Pure Rust (edition 2021, 100% Rust per repo language stats) with libc 0.2 as the sole required dependency for raw syscall bindings and constants, plus bitflags 1.0 for typed flag sets (e.g. EventSet in epoll.rs). An optional with-serde feature pulls in serde/serde_derive for structures like FamStructWrapper that benefit from (de)serialization. Dev-dependencies (serde_json, bincode) are test-only. CI is driven by the shared rust-vmm-ci submodule (with per-arch coverage_config_x86_64.json/coverage_config_aarch64.json gates), and the crate publishes to crates.io via a tag-triggered GitHub Actions workflow using OIDC auth rather than a long-lived token.

Code Quality Test coverage is broad and consistent: 20 of the 22 source files ship an inline #[cfg(test)] mod tests block exercising the public API against real kernel behavior (e.g. eventfd.rs tests read/write round-trips, epoll.rs tests add/modify/delete against real fds), and the codebase carries 96 // SAFETY: comments justifying every unsafe block that crosses into raw libc calls — a discipline consistently applied module to module. The crate enforces #![deny(missing_docs, missing_debug_implementations)] at the crate root, so every public item must carry doc comments and every public struct must implement Debug, which is reflected throughout (e.g. EventFd, SyscallReturnCode both derive/implement Debug). Errors are modeled as typed enums (e.g. fam::Error) rather than stringly-typed panics, and platform support is scoped explicitly via cfg gates instead of runtime checks.

API Design The public surface favors small, single-responsibility types over a unifying abstraction: EventFd::new(flag), TempFile::new_with_prefix(prefix), SyscallReturnCode(ret).into_result() are all short, idiomatic constructors/methods that map directly onto the underlying syscall, keeping the learning curve low for anyone who already knows the POSIX APIs being wrapped. Nearly every public function carries a doc comment with an # Examples block that compiles as a doctest (visible in ioctl.rs, eventfd.rs, tempfile.rs), which doubles as both documentation and a regression test. The tradeoff is breadth over cohesion — because each module wraps a distinct syscall family with its own idioms (FamStructWrapper<T> generics vs. plain EventFd structs vs. ioctl_iow_nr!-style macros), there’s no single mental model that carries across the whole crate; users typically import just the two or three modules relevant to their VMM component.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search