KVM: SVM: Issue WBINVD after deactivating an SEV guest
Currently, CLFLUSH is used to flush SEV guest memory before the guest is terminated (or a memory hotplug region is removed). However, CLFLUSH is not enough to ensure that SEV guest tagged data is flushed from the cache. With33af3a7ef9
("KVM: SVM: Reduce WBINVD/DF_FLUSH invocations"), the original WBINVD was removed. This then exposed crashes at random times because of a cache flush race with a page that had both a hypervisor and a guest tag in the cache. Restore the WBINVD when destroying an SEV guest and add a WBINVD to the svm_unregister_enc_region() function to ensure hotplug memory is flushed when removed. The DF_FLUSH can still be avoided at this point. Fixes:33af3a7ef9
("KVM: SVM: Reduce WBINVD/DF_FLUSH invocations") Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Message-Id: <c8bf9087ca3711c5770bdeaafa3e45b717dc5ef4.1584720426.git.thomas.lendacky@amd.com> Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Родитель
2da1ed62d5
Коммит
2e2409afe5
|
@ -1933,14 +1933,6 @@ static void sev_clflush_pages(struct page *pages[], unsigned long npages)
|
|||
static void __unregister_enc_region_locked(struct kvm *kvm,
|
||||
struct enc_region *region)
|
||||
{
|
||||
/*
|
||||
* The guest may change the memory encryption attribute from C=0 -> C=1
|
||||
* or vice versa for this memory range. Lets make sure caches are
|
||||
* flushed to ensure that guest data gets written into memory with
|
||||
* correct C-bit.
|
||||
*/
|
||||
sev_clflush_pages(region->pages, region->npages);
|
||||
|
||||
sev_unpin_memory(kvm, region->pages, region->npages);
|
||||
list_del(®ion->list);
|
||||
kfree(region);
|
||||
|
@ -1970,6 +1962,13 @@ static void sev_vm_destroy(struct kvm *kvm)
|
|||
|
||||
mutex_lock(&kvm->lock);
|
||||
|
||||
/*
|
||||
* Ensure that all guest tagged cache entries are flushed before
|
||||
* releasing the pages back to the system for use. CLFLUSH will
|
||||
* not do this, so issue a WBINVD.
|
||||
*/
|
||||
wbinvd_on_all_cpus();
|
||||
|
||||
/*
|
||||
* if userspace was terminated before unregistering the memory regions
|
||||
* then lets unpin all the registered memory.
|
||||
|
@ -7288,6 +7287,13 @@ static int svm_unregister_enc_region(struct kvm *kvm,
|
|||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that all guest tagged cache entries are flushed before
|
||||
* releasing the pages back to the system for use. CLFLUSH will
|
||||
* not do this, so issue a WBINVD.
|
||||
*/
|
||||
wbinvd_on_all_cpus();
|
||||
|
||||
__unregister_enc_region_locked(kvm, region);
|
||||
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
|
Загрузка…
Ссылка в новой задаче