]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: x86: Check EMULTYPE_WRITE_PF_TO_SP before unprotecting gfn
authorSean Christopherson <seanjc@google.com>
Sat, 31 Aug 2024 00:15:31 +0000 (17:15 -0700)
committerSean Christopherson <seanjc@google.com>
Tue, 10 Sep 2024 03:16:31 +0000 (20:16 -0700)
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>
arch/x86/kvm/x86.c

index 1e9c5ef4a9f588cf4263938cc9bd40a05c228244..7170eee23597a4f2241a71dd709dd7fc1db11ddc 100644 (file)
@@ -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);