Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a05499b2 authored by Alper Gun's avatar Alper Gun Committed by Greg Kroah-Hartman
Browse files

KVM: SVM: Call SEV Guest Decommission if ASID binding fails



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: 59414c98 ("KVM: SVM: Add support for KVM_SEV_LAUNCH_START command")
Reported-by: default avatarPeter Gonda <pgonda@google.com>
Signed-off-by: default avatarAlper Gun <alpergun@google.com>
Reviewed-by: default avatarMarc Orr <marcorr@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Message-Id: <20210610174604.2554090-1-alpergun@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 58356f44
Loading
Loading
Loading
Loading
+21 −11
Original line number Diff line number Diff line
@@ -1794,9 +1794,25 @@ static void sev_asid_free(struct kvm *kvm)
	__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 *kvm, unsigned int handle)
	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 *kvm, struct kvm_sev_cmd *argp)

	/* 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;