From 1eaa1cb095ba3d1877fced8a7d6b087431d9afca Mon Sep 17 00:00:00 2001 From: Steven Malis Date: Thu, 23 Jul 2026 15:42:20 -0400 Subject: [PATCH] virt_kvm: Validate MSR accesses --- vm/kvm/src/lib.rs | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/vm/kvm/src/lib.rs b/vm/kvm/src/lib.rs index 84ab6451c0..f394e07190 100644 --- a/vm/kvm/src/lib.rs +++ b/vm/kvm/src/lib.rs @@ -328,6 +328,15 @@ pub enum Error { GetMsrs(#[source] nix::Error), #[error("SetMsrs")] SetMsrs(#[source] nix::Error), + #[error( + "MSR access only processed {completed} of {requested} entries (first failed MSR: {failed_msr:#x}, write={write})" + )] + IncompleteMsrs { + write: bool, + completed: usize, + requested: usize, + failed_msr: u32, + }, #[error("SetupMce")] SetupMce(#[source] nix::Error), #[error("GetMceCapSupported")] @@ -1390,9 +1399,18 @@ impl<'a> Processor<'a> { } // SAFETY: Our Msrs type puts the entries array immediately after the header in memory, as required. - unsafe { + let completed = unsafe { ioctl::kvm_get_msrs(self.get().vcpu.as_raw_fd(), &mut input.header) - .map_err(Error::GetMsrs)?; + .map_err(Error::GetMsrs)? + } as usize; + assert!(completed <= msrs.len()); + if completed < msrs.len() { + return Err(Error::IncompleteMsrs { + requested: msrs.len(), + completed, + failed_msr: msrs.get(completed).copied().unwrap(), + write: false, + }); } for (v, e) in values.iter_mut().zip(&input.entries) { *v = e.data; @@ -1426,9 +1444,18 @@ impl<'a> Processor<'a> { } // SAFETY: Our Msrs type puts the entries array immediately after the header in memory, as required. - unsafe { + let completed = unsafe { ioctl::kvm_set_msrs(self.get().vcpu.as_raw_fd(), &input.header) - .map_err(Error::SetMsrs)?; + .map_err(Error::SetMsrs)? + } as usize; + assert!(completed <= msrs.len()); + if completed < msrs.len() { + return Err(Error::IncompleteMsrs { + requested: msrs.len(), + completed, + failed_msr: msrs.get(completed).copied().unwrap().0, + write: true, + }); } Ok(()) }