mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
KVM: VMX: Synthesize nested EPT violation GVA_IS_VALID/GVA_TRANSLATED bits
When injecting an EPT Violation into L2 in response to a fault detected while emulating an L2 GVA access, synthesize the GVA_IS_VALID and GVA_TRANSLATED bits using information provided by the walker, instead of pulling the bits from vmcs02.EXIT_QUALIFICATION. The information in vmcs02.EXIT_QUALIFICATION is valid/correct if and only if the fault being injected into L1 is the direct result of an EPT Violation VM-Exit from L2. E.g. if KVM is emulating an I/O instruction and the memory operand's translation through L1's EPT fails, using vmcs02.EXIT_QUALIFICATION is wrong as the semantics for EXIT_QUALIFICATION would be for an I/O exit, not an EPT Violation exit. Opportunistically clean up the formatting for creating the mask of bits to pull from vmcs02.EXIT_QUALIFICATION. Signed-off-by: Kevin Cheng <chengkev@google.com> [sean: use plumbed in @access bits, massage changelog] Link: https://patch.msgid.link/20260522232701.3671446-5-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
parent
297c2fe249
commit
96b067b59a
|
|
@ -502,7 +502,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
|||
* [2:0] - Derive from the access bits. The exit_qualification might be
|
||||
* out of date if it is serving an EPT misconfiguration.
|
||||
* [5:3] - Calculated by the page walk of the guest EPT page tables
|
||||
* [7:11] - Derived from [7:11] of real exit_qualification
|
||||
* [7:8] - Derived from "fault stage" access bits
|
||||
* [9:11] - Derived from [9:11] of real exit_qualification
|
||||
*
|
||||
* The other bits are set to 0.
|
||||
*/
|
||||
|
|
@ -516,6 +517,14 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
|||
else
|
||||
walker->fault.exit_qualification |= EPT_VIOLATION_ACC_READ;
|
||||
|
||||
/*
|
||||
* KVM doesn't emulate features that access GPAs directly, e.g.
|
||||
* Intel Processor Trace. Assume the GVA is always valid; when
|
||||
* propagating faults from hardware, KVM will discard this info
|
||||
* and use the EXIT_QUALIFICATION bits from the VMCS.
|
||||
*/
|
||||
walker->fault.exit_qualification |= EPT_VIOLATION_GVA_IS_VALID;
|
||||
|
||||
/*
|
||||
* Accesses to guest paging structures are either "reads" or
|
||||
* "read+write" accesses, so consider them the latter if write_fault
|
||||
|
|
@ -523,6 +532,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
|
|||
*/
|
||||
if (access & PFERR_GUEST_PAGE_MASK)
|
||||
walker->fault.exit_qualification |= EPT_VIOLATION_ACC_READ;
|
||||
else
|
||||
walker->fault.exit_qualification |= EPT_VIOLATION_GVA_TRANSLATED;
|
||||
|
||||
/*
|
||||
* Note, pte_access holds the raw RWX bits from the EPTE, not
|
||||
|
|
|
|||
|
|
@ -445,13 +445,29 @@ static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu,
|
|||
exit_qualification = 0;
|
||||
} else {
|
||||
u64 mask = EPT_VIOLATION_GVA_IS_VALID |
|
||||
EPT_VIOLATION_GVA_TRANSLATED;
|
||||
EPT_VIOLATION_GVA_TRANSLATED;
|
||||
|
||||
if (vmx->nested.msrs.ept_caps & VMX_EPT_ADVANCED_VMEXIT_INFO_BIT)
|
||||
mask |= EPT_VIOLATION_GVA_USER |
|
||||
EPT_VIOLATION_GVA_WRITABLE |
|
||||
EPT_VIOLATION_GVA_NX;
|
||||
exit_qualification = fault->exit_qualification;
|
||||
exit_qualification |= vmx_get_exit_qual(vcpu) & mask;
|
||||
EPT_VIOLATION_GVA_WRITABLE |
|
||||
EPT_VIOLATION_GVA_NX;
|
||||
|
||||
exit_qualification = fault->exit_qualification & ~mask;
|
||||
|
||||
/*
|
||||
* Use the EXIT_QUALIFICATION from the VMCS if and only
|
||||
* if the hardware VM-Exit from L2 was an EPT Violation.
|
||||
* If the fault is synthesized, then EXIT_QUALIFICATION
|
||||
* is stale and/or holds entirely different data. And
|
||||
* conversely, KVM _must_ rely on EXIT_QUALIFICATION if
|
||||
* the fault came from hardware, because KVM only sees
|
||||
* and walks the faulting GPA.
|
||||
*/
|
||||
if (from_hardware)
|
||||
exit_qualification |= vmx_get_exit_qual(vcpu) & mask;
|
||||
else
|
||||
exit_qualification |= fault->exit_qualification & mask;
|
||||
|
||||
vm_exit_reason = EXIT_REASON_EPT_VIOLATION;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user