[PATCH 5.4 3/4] KVM: SVM: Call SEV Guest Decommission if ASID binding fails
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: 2021-07-09 13:20:38
Also in:
lkml
From: Alper Gun <redacted>
commit 934002cd660b035b926438244b4294e647507e13 upstream.
Send SEV_CMD_DECOMMISSION command to PSP firmware if ASID binding
fails. If a failure happens after a successful LAUNCH_START command,
a decommission command should be executed. Otherwise, guest context
will be unfreed inside the AMD SP. After the firmware will not have
memory to allocate more SEV guest context, LAUNCH_START command will
begin to fail with SEV_RET_RESOURCE_LIMIT error.
The existing code calls decommission inside sev_unbind_asid, but it is
not called if a failure happens before guest activation succeeds. If
sev_bind_asid fails, decommission is never called. PSP firmware has a
limit for the number of guests. If sev_asid_binding fails many times,
PSP firmware will not have resources to create another guest context.
Cc: stable@vger.kernel.org
Fixes: 59414c989220 ("KVM: SVM: Add support for KVM_SEV_LAUNCH_START command")
Reported-by: Peter Gonda <redacted>
Signed-off-by: Alper Gun <redacted>
Reviewed-by: Marc Orr <redacted>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: [ref]
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
arch/x86/kvm/svm.c | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c@@ -1794,9 +1794,25 @@ static void sev_asid_free(struct kvm *kv __sev_asid_free(sev->asid); } -static void sev_unbind_asid(struct kvm *kvm, unsigned int handle) +static void sev_decommission(unsigned int handle) { struct sev_data_decommission *decommission; + + if (!handle) + return; + + decommission = kzalloc(sizeof(*decommission), GFP_KERNEL); + if (!decommission) + return; + + decommission->handle = handle; + sev_guest_decommission(decommission, NULL); + + kfree(decommission); +} + +static void sev_unbind_asid(struct kvm *kvm, unsigned int handle) +{ struct sev_data_deactivate *data; if (!handle)
@@ -1814,15 +1830,7 @@ static void sev_unbind_asid(struct kvm * sev_guest_df_flush(NULL); kfree(data); - decommission = kzalloc(sizeof(*decommission), GFP_KERNEL); - if (!decommission) - return; - - /* decommission handle */ - decommission->handle = handle; - sev_guest_decommission(decommission, NULL); - - kfree(decommission); + sev_decommission(handle); } static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr,
@@ -6476,8 +6484,10 @@ static int sev_launch_start(struct kvm * /* Bind ASID to this guest */ ret = sev_bind_asid(kvm, start->handle, error); - if (ret) + if (ret) { + sev_decommission(start->handle); goto e_free_session; + } /* return handle to userspace */ params.handle = start->handle;