Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: X86: Fix missed remote tlb flush in rmap_write_protect()

When kvm->tlbs_dirty > 0, some rmaps might have been deleted
without flushing tlb remotely after kvm_sync_page(). If @gfn
was writable before and it's rmaps was deleted in kvm_sync_page(),
and if the tlb entry is still in a remote running VCPU, the @gfn
is not safely protected.

To fix the problem, kvm_sync_page() does the remote flush when
needed to avoid the problem.

Fixes: a4ee1ca4a36e ("KVM: MMU: delay flush all tlbs on sync_page path")
Signed-off-by: Lai Jiangshan <laijs@linux.alibaba.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20210918005636.3675-2-jiangshanlai@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Lai Jiangshan and committed by
Paolo Bonzini
f8160295 faf6b755

+2 -21
+2 -21
arch/x86/kvm/mmu/paging_tmpl.h
··· 1047 1047 * Using the cached information from sp->gfns is safe because: 1048 1048 * - The spte has a reference to the struct page, so the pfn for a given gfn 1049 1049 * can't change unless all sptes pointing to it are nuked first. 1050 - * 1051 - * Note: 1052 - * We should flush all tlbs if spte is dropped even though guest is 1053 - * responsible for it. Since if we don't, kvm_mmu_notifier_invalidate_page 1054 - * and kvm_mmu_notifier_invalidate_range_start detect the mapping page isn't 1055 - * used by guest then tlbs are not flushed, so guest is allowed to access the 1056 - * freed pages. 1057 - * And we increase kvm->tlbs_dirty to delay tlbs flush in this case. 1058 1050 */ 1059 1051 static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) 1060 1052 { ··· 1099 1107 return 0; 1100 1108 1101 1109 if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) { 1102 - /* 1103 - * Update spte before increasing tlbs_dirty to make 1104 - * sure no tlb flush is lost after spte is zapped; see 1105 - * the comments in kvm_flush_remote_tlbs(). 1106 - */ 1107 - smp_wmb(); 1108 - vcpu->kvm->tlbs_dirty++; 1110 + set_spte_ret |= SET_SPTE_NEED_REMOTE_TLB_FLUSH; 1109 1111 continue; 1110 1112 } 1111 1113 ··· 1114 1128 1115 1129 if (gfn != sp->gfns[i]) { 1116 1130 drop_spte(vcpu->kvm, &sp->spt[i]); 1117 - /* 1118 - * The same as above where we are doing 1119 - * prefetch_invalid_gpte(). 1120 - */ 1121 - smp_wmb(); 1122 - vcpu->kvm->tlbs_dirty++; 1131 + set_spte_ret |= SET_SPTE_NEED_REMOTE_TLB_FLUSH; 1123 1132 continue; 1124 1133 } 1125 1134