From cf248db107fd3975a6ad257498148873348db3a6 Mon Sep 17 00:00:00 2001 From: Nikita Kalyazin Date: Tue, 5 Aug 2025 15:20:09 +0000 Subject: [PATCH 1/5] fix(vmm): propagate errors in secret freedom Return errors up the stack instead of panicking. Signed-off-by: Nikita Kalyazin --- src/vmm/src/builder.rs | 19 +++++++++---------- src/vmm/src/lib.rs | 2 +- src/vmm/src/persist.rs | 4 +--- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index 64211024362..246911df480 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -67,7 +67,7 @@ use crate::vmm_config::instance_info::InstanceInfo; use crate::vmm_config::machine_config::MachineConfigError; use crate::vmm_config::snapshot::{LoadSnapshotParams, MemBackendType}; use crate::vstate::kvm::Kvm; -use crate::vstate::memory::{MaybeBounce, create_memfd}; +use crate::vstate::memory::{MaybeBounce, MemoryError, create_memfd}; use crate::vstate::vcpu::{Vcpu, VcpuError}; use crate::vstate::vm::{GUEST_MEMFD_FLAG_NO_DIRECT_MAP, GUEST_MEMFD_FLAG_SUPPORT_SHARED, Vm}; use crate::{EventManager, Vmm, VmmError, device_manager}; @@ -482,10 +482,10 @@ pub enum BuildMicrovmFromSnapshotError { /// Failed to load guest memory: {0} GuestMemory(#[from] BuildMicrovmFromSnapshotErrorGuestMemoryError), /// Userfault bitmap memfd error: {0} - UserfaultBitmapMemfd(#[from] crate::vstate::memory::MemoryError), + UserfaultBitmapMemfd(#[from] MemoryError), } -fn memfd_to_slice(memfd: &Option) -> Option<&mut [u8]> { +fn memfd_to_slice(memfd: &Option) -> Result, MemoryError> { if let Some(bitmap_file) = memfd { let len = u64_to_usize( bitmap_file @@ -507,16 +507,15 @@ fn memfd_to_slice(memfd: &Option) -> Option<&mut [u8]> { }; if bitmap_addr == libc::MAP_FAILED { - panic!( - "Failed to mmap userfault bitmap file: {}", - std::io::Error::last_os_error() - ); + return Err(MemoryError::Mmap(std::io::Error::last_os_error())); } // SAFETY: `bitmap_addr` is a valid memory address returned by `mmap`. - Some(unsafe { std::slice::from_raw_parts_mut(bitmap_addr.cast(), len) }) + Ok(Some(unsafe { + std::slice::from_raw_parts_mut(bitmap_addr.cast(), len) + })) } else { - None + Ok(None) } } @@ -616,7 +615,7 @@ pub fn build_microvm_from_snapshot( } }; - let mut userfault_bitmap = memfd_to_slice(&userfault_bitmap_memfd); + let mut userfault_bitmap = memfd_to_slice(&userfault_bitmap_memfd)?; if let Some(ref mut slice) = userfault_bitmap { // Set all bits so a fault on any page will cause a VM exit slice.fill(0xffu8); diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index eda747bc3a3..c32b4ed35c9 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -1037,7 +1037,7 @@ impl MutEventSubscriber for Vmm { if let Some(uffd_socket) = self.uffd_socket.as_ref() { if let Err(err) = ops.add(Events::new(uffd_socket, EventSet::IN)) { - panic!("Failed to register UFFD socket: {}", err); + error!("Failed to register UFFD socket: {}", err); } } } diff --git a/src/vmm/src/persist.rs b/src/vmm/src/persist.rs index 93c81ad3db7..4c40c7eacde 100644 --- a/src/vmm/src/persist.rs +++ b/src/vmm/src/persist.rs @@ -609,9 +609,7 @@ fn send_uffd_handshake( let backend_mappings = serde_json::to_string(backend_mappings).unwrap(); let socket = UnixStream::connect(mem_uds_path)?; - socket - .set_nonblocking(true) - .expect("Cannot set non-blocking"); + socket.set_nonblocking(true)?; socket.send_with_fds( &[backend_mappings.as_bytes()], From 859b0b40a45648b5edc412b9380ae3d74f7d3153 Mon Sep 17 00:00:00 2001 From: Nikita Kalyazin Date: Wed, 6 Aug 2025 09:11:52 +0000 Subject: [PATCH 2/5] fix(vmm): do not unwrap in gpa_to_offset Return None if file_offset() is None instead. Signed-off-by: Nikita Kalyazin --- src/vmm/src/vstate/memory.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/vmm/src/vstate/memory.rs b/src/vmm/src/vstate/memory.rs index 0f319562683..77112db802f 100644 --- a/src/vmm/src/vstate/memory.rs +++ b/src/vmm/src/vstate/memory.rs @@ -482,8 +482,9 @@ impl GuestMemoryExtension for GuestMemoryMmap { /// Convert guest physical address to file offset fn gpa_to_offset(&self, gpa: GuestAddress) -> Option { - self.find_region(gpa).map(|r| { - gpa.0 - r.start_addr().0 + r.file_offset().expect("File offset is None").start() + self.find_region(gpa).and_then(|r| { + r.file_offset() + .map(|file_offset| gpa.0 - r.start_addr().0 + file_offset.start()) }) } From ce8b2a60cdc4df6a41c64ffec814d902f8ba3a77 Mon Sep 17 00:00:00 2001 From: Nikita Kalyazin Date: Wed, 6 Aug 2025 09:15:35 +0000 Subject: [PATCH 3/5] fix(vmm): write_all in process_vcpu_userfault This is to make sure that we always write the entire FaultRequest message even if the syscall was interrupted. Signed-off-by: Nikita Kalyazin --- src/vmm/src/lib.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index c32b4ed35c9..ee65c85f49a 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -819,21 +819,11 @@ impl Vmm { let fault_request_json = serde_json::to_string(&fault_request).expect("Failed to serialize fault request"); - let written = self - .uffd_socket + self.uffd_socket .as_ref() .expect("Uffd socket is not set") - .write(fault_request_json.as_bytes()) + .write_all(fault_request_json.as_bytes()) .expect("Failed to write to uffd socket"); - - if written != fault_request_json.len() { - panic!( - "Failed to write the entire fault request to the uffd socket: expected {}, \ - written {}", - fault_request_json.len(), - written - ); - } } fn active_event_in_uffd_socket(&self, source: RawFd, event_set: EventSet) -> bool { From 0b1085b20d0f9691e9f5adfb4edb869db36d799c Mon Sep 17 00:00:00 2001 From: Nikita Kalyazin Date: Wed, 6 Aug 2025 09:23:14 +0000 Subject: [PATCH 4/5] fix(vmm): handle EINTR in process_uffd_socket Make sure we continue reading the FaultReply if the syscall was interrupted. Signed-off-by: Nikita Kalyazin --- src/vmm/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index ee65c85f49a..e24a9d2c84e 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -852,6 +852,7 @@ impl Vmm { break; } } + Err(e) if e.kind() == io::ErrorKind::Interrupted => continue, Err(e) => panic!("Read error: {}", e), } } From 6c9198c6c20400c13841a89c10e4b084c92606b4 Mon Sep 17 00:00:00 2001 From: Nikita Kalyazin Date: Wed, 6 Aug 2025 09:26:27 +0000 Subject: [PATCH 5/5] fix(vmm): simplify vcpus_handles dereferencing in process_uffd_socket Get rid of the expect by using indexing. Signed-off-by: Nikita Kalyazin --- src/vmm/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index e24a9d2c84e..097747cbd48 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -866,11 +866,7 @@ impl Vmm { match result { Ok(fault_reply) => { let vcpu = fault_reply.vcpu.expect("vCPU must be set"); - - self.vcpus_handles - .get(vcpu as usize) - .expect("Invalid vcpu index") - .send_userfault_resolved(); + self.vcpus_handles[vcpu as usize].send_userfault_resolved(); total_consumed = parser.byte_offset(); }