Skip to content

Commit

Permalink
KVM: SVM: Guard against DEACTIVATE when performing WBINVD/DF_FLUSH
Browse files Browse the repository at this point in the history
The SEV firmware DEACTIVATE command disassociates an SEV guest from an
ASID, clears the WBINVD indicator on all threads and indicates that the
SEV firmware DF_FLUSH command must be issued before the ASID can be
re-used. The SEV firmware DF_FLUSH command will return an error if a
WBINVD has not been performed on every thread before it has been invoked.
A window exists between the WBINVD and the invocation of the DF_FLUSH
command where an SEV firmware DEACTIVATE command could be invoked on
another thread, clearing the WBINVD indicator. This will cause the
subsequent SEV firmware DF_FLUSH command to fail which, in turn, results
in the SEV firmware ACTIVATE command failing for the reclaimed ASID.
This results in the SEV guest failing to start.

Use a mutex to close the WBINVD/DF_FLUSH window by obtaining the mutex
before the DEACTIVATE and releasing it after the DF_FLUSH. This ensures
that any DEACTIVATE cannot run before a DF_FLUSH has completed.

Fixes: 59414c9 ("KVM: SVM: Add support for KVM_SEV_LAUNCH_START command")
Tested-by: David Rientjes <rientjes@google.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
Tom Lendacky authored and Paolo Bonzini committed Oct 22, 2019
1 parent e3b9a9e commit 83af5e6
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ enum {

#define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL

static DEFINE_MUTEX(sev_deactivate_lock);
static DEFINE_MUTEX(sev_bitmap_lock);
static unsigned int max_sev_asid;
static unsigned int min_sev_asid;
Expand Down Expand Up @@ -1756,10 +1757,20 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle)

/* deactivate handle */
data->handle = handle;

/*
* Guard against a parallel DEACTIVATE command before the DF_FLUSH
* command has completed.
*/
mutex_lock(&sev_deactivate_lock);

sev_guest_deactivate(data, NULL);

wbinvd_on_all_cpus();
sev_guest_df_flush(NULL);

mutex_unlock(&sev_deactivate_lock);

kfree(data);

decommission = kzalloc(sizeof(*decommission), GFP_KERNEL);
Expand Down Expand Up @@ -6318,9 +6329,18 @@ static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error)
int asid = sev_get_asid(kvm);
int ret;

/*
* Guard against a DEACTIVATE command before the DF_FLUSH command
* has completed.
*/
mutex_lock(&sev_deactivate_lock);

wbinvd_on_all_cpus();

ret = sev_guest_df_flush(error);

mutex_unlock(&sev_deactivate_lock);

if (ret)
return ret;

Expand Down

0 comments on commit 83af5e6

Please sign in to comment.