hypervisor: mshv: Validate GPA mapping with GvaGpaValid flag

The GvaGpaValid flag in the intercept message indicates whether
the provided GPA corresponds to the decoded GVA. Without checking
this flag, the emulator may incorrectly use a stale GPA mapping
when the hypervisor invalidates it.

Add a check for the GvaGpaValid flag before using the cached
(GVA, GPA) mapping. If the flag is clear, use a sentinel value
to force translate() to perform a proper hypercall-based
translation instead of using an invalid cached mapping.

Signed-off-by: Pedro Barbuda <pbarbuda@microsoft.com>
Signed-off-by: Muminul Islam <muislam@microsoft.com>
This commit is contained in:
Muminul Islam
2026-04-24 14:49:33 -07:00
committed by Wei Liu
parent 326cd88074
commit 842d02fdd9
2 changed files with 25 additions and 3 deletions

View File

@@ -720,11 +720,28 @@ impl cpu::Vcpu for MshvVcpu {
let gva = info.guest_virtual_address;
let gpa = info.guest_physical_address;
debug!("Exit ({msg_type:?}) GVA {gva:x} GPA {gpa:x}");
// The GvaGpaValid flag indicates that the GPA in the intercept
// message corresponds to the GVA in the message. If that flag
// is set, and the GVA in the message matches the GVA in the decoded
// instruction, then the emulator can use the GPA provided by
// the hypervisor. Otherwise, the emulator must translate the GVA
// via a hypercall.
// SAFETY: accessing the bitfield union variant.
let gva_gpa_valid =
unsafe { info.memory_access_info.__bindgen_anon_1.gva_gpa_valid() != 0 };
debug!(
"Exit ({msg_type:?}) GVA {gva:x} GPA {gpa:x} \
gva_gpa_valid={gva_gpa_valid}"
);
let mut context = MshvEmulatorContext {
vcpu: self,
map: (gva, gpa),
map: if gva_gpa_valid {
(gva, gpa)
} else {
(u64::MAX, 0)
},
};
let old_state = context

View File

@@ -19,7 +19,12 @@ pub struct MshvEmulatorContext<'a> {
}
impl MshvEmulatorContext<'_> {
// Do the actual gva -> gpa translation
// Do the actual gva -> gpa translation.
//
// When the hypervisor sets GvaGpaValid in the intercept message, `map`
// caches the (gva, gpa) pair as a fast path that avoids a translate
// hypercall. When the flag is clear, `map` is set to a sentinel
// (u64::MAX, 0) so this shortcut never fires.
#[allow(non_upper_case_globals)]
fn translate(&self, gva: u64, flags: u32) -> Result<u64, PlatformError> {
if self.map.0 == gva {