KVM: x86/mmu: WARN and flush if resolving a TDP MMU fault clears MMU-writable
authorSean Christopherson <seanjc@google.com>
Fri, 11 Oct 2024 02:10:40 +0000 (19:10 -0700)
committerSean Christopherson <seanjc@google.com>
Wed, 30 Oct 2024 21:46:46 +0000 (14:46 -0700)
Do a remote TLB flush if installing a leaf SPTE overwrites an existing
leaf SPTE (with the same target pfn, which is enforced by a BUG() in
handle_changed_spte()) and clears the MMU-Writable bit.  Since the TDP MMU
passes ACC_ALL to make_spte(), i.e. always requests a Writable SPTE, the
only scenario in which make_spte() should create a !MMU-Writable SPTE is
if the gfn is write-tracked or if KVM is prefetching a SPTE.

When write-protecting for write-tracking, KVM must hold mmu_lock for write,
i.e. can't race with a vCPU faulting in the SPTE.  And when prefetching a
SPTE, the TDP MMU takes care to avoid clobbering a shadow-present SPTE,
i.e. it should be impossible to replace a MMU-writable SPTE with a
!MMU-writable SPTE when handling a TDP MMU fault.

Cc: David Matlack <dmatlack@google.com>
Cc: Yan Zhao <yan.y.zhao@intel.com>
Link: https://lore.kernel.org/r/20241011021051.1557902-9-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/mmu/tdp_mmu.c

index 9c66be7fb002ef30b8992d1d95b6eacd652e3be9..bc9e2f50dc80c839e4ef28fa04a988f070602a49 100644 (file)
@@ -1033,7 +1033,9 @@ static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu,
        else if (tdp_mmu_set_spte_atomic(vcpu->kvm, iter, new_spte))
                return RET_PF_RETRY;
        else if (is_shadow_present_pte(iter->old_spte) &&
-                !is_last_spte(iter->old_spte, iter->level))
+                (!is_last_spte(iter->old_spte, iter->level) ||
+                 WARN_ON_ONCE(is_mmu_writable_spte(iter->old_spte) &&
+                              !is_mmu_writable_spte(new_spte))))
                kvm_flush_remote_tlbs_gfn(vcpu->kvm, iter->gfn, iter->level);
 
        /*