-
Notifications
You must be signed in to change notification settings - Fork 189
write VMSA to crash page #3386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
write VMSA to crash page #3386
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -27,6 +27,7 @@ use crate::devmsr; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::processor::UhHypercallHandler; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::processor::UhProcessor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use crate::processor::hardware_cvm::apic::ApicBacking; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use core::mem::size_of; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use cvm_tracing::CVM_ALLOWED; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use cvm_tracing::CVM_CONFIDENTIAL; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use hcl::protocol::hcl_intr_offload_flags; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -51,6 +52,7 @@ use hvdef::hypercall::HypercallOutput; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use inspect::Inspect; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use inspect::InspectMut; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use inspect_counters::Counter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use user_driver::memory::MemoryBlock; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use virt::EmulatorMonitorSupport; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use virt::Processor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| use virt::VpHaltReason; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -115,6 +117,10 @@ pub struct SnpBacked { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hv_sint_notifications: u16, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| general_stats: VtlArray<GeneralStats, 2>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit_stats: VtlArray<ExitStats, 2>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[inspect(skip)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crash_vmsa_page: MemoryBlock, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[inspect(hex)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crash_vmsa_page_pa: u64, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #[inspect(flatten)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cvm: UhCvmVpState, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -174,6 +180,55 @@ impl SnpBacked { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pub fn shared_pages_required_per_cpu() -> u64 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UhDirectOverlay::Count as u64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fn update_vmsa_crash_page(this: &mut UhProcessor<'_, Self>, vtl: GuestVtl) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let crash_page_pa = this.backing.crash_vmsa_page_pa; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let crash_page_pa = this.backing.crash_vmsa_page_pa; | |
| let crash_page_pa = this.backing.crash_vmsa_page_pa; | |
| assert!(size_of::<SevVmsa>() <= HV_PAGE_SIZE as usize); |
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HV_X64_MSR_GUEST_CRASH_P3/P4 are defined as the crash-message GPA/length (see hvdef::GuestCrashCtl docs), and the VTL crash notification path in processor/mod.rs reads crash_reg[3]/[4] to fetch that message. Overwriting this.crash_reg[3]/[4] here will clobber guest-provided crash message parameters and can cause crash notifications to read from the wrong GPA.
Consider keeping the guest crash registers exclusively guest-owned (only updated on guest MSR writes), and publishing the VMSA snapshot pointer via a separate mechanism/state that doesn’t reuse the crash-message registers.
| let vmsa_size = size_of::<SevVmsa>() as u64; | |
| // Keep the crash-page register pair pointing to a host-visible page | |
| // so a hypervisor debugger can find the latest VMSA snapshot. | |
| this.crash_reg[3] = crash_page_pa; | |
| this.crash_reg[4] = vmsa_size; | |
| for target_vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] { | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP3, | |
| crash_page_pa.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to publish crash page address" | |
| ); | |
| } | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP4, | |
| vmsa_size.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to publish crash page size" | |
| ); | |
| } | |
| } | |
| // Do not reuse the guest crash-message registers (P3/P4) to publish | |
| // the VMSA snapshot location. Those registers are guest-owned and are | |
| // consumed by the crash notification path as the crash-message GPA and | |
| // length. |
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This copies the full VMSA into a shared/host-visible page (“so a hypervisor debugger can find…”). On SNP, that effectively exports guest register state (and the register protection nonce) to the untrusted host/hypervisor, which is a major confidentiality risk.
This should be gated behind an explicit debug/diagnostics opt-in (and ideally compiled/available only in debug builds), or restricted to a crash-only path where the guest has already decided to disclose crash details.
| // Keep the crash-page register pair pointing to a host-visible page | |
| // so a hypervisor debugger can find the latest VMSA snapshot. | |
| this.crash_reg[3] = crash_page_pa; | |
| this.crash_reg[4] = vmsa_size; | |
| for target_vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] { | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP3, | |
| crash_page_pa.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to publish crash page address" | |
| ); | |
| } | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP4, | |
| vmsa_size.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to publish crash page size" | |
| ); | |
| } | |
| } | |
| let vmsa = this.runner.vmsa(vtl); | |
| let src = vmsa.as_bytes(); | |
| if let Err(err) = this.shared.cvm.shared_memory.write_at(crash_page_pa, src) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| crash_page_pa, | |
| "failed to write crash VMSA page" | |
| ); | |
| if cfg!(debug_assertions) { | |
| // Only publish a host-visible VMSA snapshot in debug builds. | |
| // In production SNP guests this would disclose sensitive guest | |
| // register state to the untrusted host/hypervisor. | |
| this.crash_reg[3] = crash_page_pa; | |
| this.crash_reg[4] = vmsa_size; | |
| for target_vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] { | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP3, | |
| crash_page_pa.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to publish crash page address" | |
| ); | |
| } | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP4, | |
| vmsa_size.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to publish crash page size" | |
| ); | |
| } | |
| } | |
| let vmsa = this.runner.vmsa(vtl); | |
| let src = vmsa.as_bytes(); | |
| if let Err(err) = this.shared.cvm.shared_memory.write_at(crash_page_pa, src) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| crash_page_pa, | |
| "failed to write crash VMSA page" | |
| ); | |
| } | |
| } else { | |
| // Do not expose a host-visible VMSA page in non-debug builds. | |
| this.crash_reg[3] = 0; | |
| this.crash_reg[4] = 0; | |
| for target_vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] { | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP3, | |
| 0.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to clear crash page address" | |
| ); | |
| } | |
| if let Err(err) = this.runner.set_vp_register( | |
| target_vtl, | |
| HvX64RegisterName::GuestCrashP4, | |
| 0.into(), | |
| ) { | |
| tracelimit::warn_ratelimited!( | |
| CVM_ALLOWED, | |
| ?err, | |
| ?target_vtl, | |
| "failed to clear crash page size" | |
| ); | |
| } | |
| } |
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update_vmsa_crash_page() is called on every VP exit (right after run()), which means an extra ~page-sized copy per exit. On workloads with frequent exits this can become a noticeable overhead.
If this is intended primarily for post-mortem/debugging, consider updating the crash page only when a crash is detected (e.g., on guest crash MSR write), or at a lower frequency / behind a diagnostics flag.
| SnpBacked::update_vmsa_crash_page(self, entered_from_vtl); | |
| if has_intercept { | |
| SnpBacked::update_vmsa_crash_page(self, entered_from_vtl); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as_bytes()exposes the complete raw VMSA image (including the register protection nonce and XOR-masked protected fields). Given how sensitive this data is, the doc comment should explicitly call out that callers must treat the returned bytes as highly confidential and should not copy it into host-visible/shared memory unless explicitly intended.If possible, also consider whether this needs to be a public API vs. restricted to the crates that implement low-level diagnostics.