Skip to content

Commit

Permalink
KVM: SVM: Issue WBINVD after deactivating an SEV guest
Browse files Browse the repository at this point in the history
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.

With 33af3a7 ("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: 33af3a7 ("KVM: SVM: Reduce WBINVD/DF_FLUSH invocations")
Signed-off-by: Tom Lendacky <[email protected]>
Message-Id: <c8bf9087ca3711c5770bdeaafa3e45b717dc5ef4.1584720426.git.thomas.lendacky@amd.com>
Cc: [email protected]
Signed-off-by: Paolo Bonzini <[email protected]>
  • Loading branch information
tlendacky authored and bonzini committed Mar 23, 2020
1 parent 2da1ed6 commit 2e2409a
Showing 1 changed file with 14 additions and 8 deletions.
22 changes: 14 additions & 8 deletions arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&region->list);
kfree(region);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 2e2409a

Please sign in to comment.