Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/vmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ serde = { version = "1.0.228", features = ["derive", "rc"] }
serde_json = "1.0.149"
slab = "0.4.12"
thiserror = "2.0.18"
userfaultfd = "0.9.0"
userfaultfd = { version = "0.9.0", features = ["linux5_7"] }
utils = { path = "../utils" }
uuid = "1.23.0"
vhost = { version = "0.15.0", features = ["vhost-user-frontend"] }
Expand Down
20 changes: 17 additions & 3 deletions src/vmm/src/persist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex};

use semver::Version;
use serde::{Deserialize, Serialize};
use userfaultfd::{FeatureFlags, Uffd, UffdBuilder};
use userfaultfd::{FeatureFlags, RegisterMode, Uffd, UffdBuilder};
use vmm_sys_util::sock_ctrl_msg::ScmSocket;

#[cfg(target_arch = "aarch64")]
Expand Down Expand Up @@ -553,9 +553,23 @@ fn guest_memory_from_uffd(
.create()
.map_err(GuestMemoryFromUffdError::Create)?;

// Register every region for both MISSING and WRITE_PROTECT faults.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing WP feature negotiation during UFFDIO_API handshake

Medium Severity

The code registers regions with RegisterMode::WRITE_PROTECT but never negotiates FeatureFlags::PAGEFAULT_FLAG_WP during the UFFDIO_API handshake. The Linux man page states the user needs to check availability of UFFD_FEATURE_PAGEFAULT_FLAG_WP via UFFDIO_API before using write-protect mode. Adding this to require_features would also provide an early, clear failure on platforms that lack WP support instead of a less informative error at registration time.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 32330a4. Configure here.

//
// MISSING is needed so the orchestrator's UFFD handler is woken up the first time the guest
// touches a page that has not yet been populated from the snapshot's memory file.
//
// WRITE_PROTECT is needed so the handler can keep pages it serves in a write-protected state
// (via UFFDIO_COPY_MODE_WP) and observe subsequent writes as new faults — the standard CoW
// tracking pattern that lets the orchestrator know which pages got dirtied after restore.
// Without WRITE_PROTECT registration, UFFDIO_COPY with MODE_WP fails synchronously with
// EINVAL on the very first read fault, breaking the snapshot resume path.
for mem_region in guest_memory.iter() {
uffd.register(mem_region.as_ptr().cast(), mem_region.size() as _)
.map_err(GuestMemoryFromUffdError::Register)?;
uffd.register_with_mode(
mem_region.as_ptr().cast(),
mem_region.size() as _,
RegisterMode::MISSING | RegisterMode::WRITE_PROTECT,
)
.map_err(GuestMemoryFromUffdError::Register)?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UFFD WRITE_PROTECT registration breaks aarch64 on kernels below 6.10

High Severity

Unconditionally registering with RegisterMode::WRITE_PROTECT will cause UFFDIO_REGISTER to fail with EINVAL on aarch64 with kernels before 6.10, because arm64 userfaultfd write-protect page table support (pgtable_uffd_wp_supported()) was only added in Linux 6.10. Firecracker supports aarch64 on kernels 5.10 and 6.1, both of which lack this support. This is a regression that breaks all UFFD-based snapshot restores on aarch64, not just WP-tracking ones, since the registration itself fails.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 32330a4. Configure here.

}

send_uffd_handshake(mem_uds_path, &backend_mappings, &uffd)?;
Expand Down
Loading