mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 18:40:25 -04:00
KVM: x86: Check EMULTYPE_WRITE_PF_TO_SP before unprotecting gfn
Don't bother unprotecting the target gfn if EMULTYPE_WRITE_PF_TO_SP is set, as KVM will simply report the emulation failure to userspace. This will allow converting reexecute_instruction() to use kvm_mmu_unprotect_gfn_instead_retry() instead of kvm_mmu_unprotect_page(). Link: https://lore.kernel.org/r/20240831001538.336683-17-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
@@ -8869,6 +8869,19 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
|
||||
if (!(emulation_type & EMULTYPE_ALLOW_RETRY_PF))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the failed instruction faulted on an access to page tables that
|
||||
* are used to translate any part of the instruction, KVM can't resolve
|
||||
* the issue by unprotecting the gfn, as zapping the shadow page will
|
||||
* result in the instruction taking a !PRESENT page fault and thus put
|
||||
* the vCPU into an infinite loop of page faults. E.g. KVM will create
|
||||
* a SPTE and write-protect the gfn to resolve the !PRESENT fault, and
|
||||
* then zap the SPTE to unprotect the gfn, and then do it all over
|
||||
* again. Report the error to userspace.
|
||||
*/
|
||||
if (emulation_type & EMULTYPE_WRITE_PF_TO_SP)
|
||||
return false;
|
||||
|
||||
if (!vcpu->arch.mmu->root_role.direct) {
|
||||
/*
|
||||
* Write permission should be allowed since only
|
||||
@@ -8894,16 +8907,13 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
|
||||
kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa));
|
||||
|
||||
/*
|
||||
* If the failed instruction faulted on an access to page tables that
|
||||
* are used to translate any part of the instruction, KVM can't resolve
|
||||
* the issue by unprotecting the gfn, as zapping the shadow page will
|
||||
* result in the instruction taking a !PRESENT page fault and thus put
|
||||
* the vCPU into an infinite loop of page faults. E.g. KVM will create
|
||||
* a SPTE and write-protect the gfn to resolve the !PRESENT fault, and
|
||||
* then zap the SPTE to unprotect the gfn, and then do it all over
|
||||
* again. Report the error to userspace.
|
||||
* Retry even if _this_ vCPU didn't unprotect the gfn, as it's possible
|
||||
* all SPTEs were already zapped by a different task. The alternative
|
||||
* is to report the error to userspace and likely terminate the guest,
|
||||
* and the last_retry_{eip,addr} checks will prevent retrying the page
|
||||
* fault indefinitely, i.e. there's nothing to lose by retrying.
|
||||
*/
|
||||
return !(emulation_type & EMULTYPE_WRITE_PF_TO_SP);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
|
||||
|
||||
Reference in New Issue
Block a user