aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorSean Christopherson <seanjc@google.com>2024-10-10 19:10:40 -0700
committerSean Christopherson <seanjc@google.com>2024-10-30 14:46:46 -0700
commit1a175082b190190d9d05a0a5927b72cbb657fd1d (patch)
treee064f9a77da38f3705364ff4f026b639c707c05c
parentKVM: x86/mmu: Fold mmu_spte_update_no_track() into mmu_spte_update() (diff)
downloadwireguard-linux-1a175082b190190d9d05a0a5927b72cbb657fd1d.tar.xz
wireguard-linux-1a175082b190190d9d05a0a5927b72cbb657fd1d.zip
KVM: x86/mmu: WARN and flush if resolving a TDP MMU fault clears MMU-writable
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>
Diffstat (limited to '')
-rw-r--r--arch/x86/kvm/mmu/tdp_mmu.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 9c66be7fb002..bc9e2f50dc80 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -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);
/*