Commit 760299a1 authored by Will Deacon's avatar Will Deacon Committed by Marc Zyngier
Browse files

KVM: arm64: Prevent teardown finalisation of referenced 'hyp_vm'



Destroying a 'hyp_vm' with an elevated referenced count in
__pkvm_finalize_teardown_vm() is only going to lead to tears.

In preparation for allowing limited references to be acquired on dying
VMs during the teardown process, factor out the handle-to-vm logic for
the teardown path and reuse it for both the 'start' and 'finalise'
stages of the teardown process.

Signed-off-by: default avatarWill Deacon <will@kernel.org>
Link: https://patch.msgid.link/20260331155056.28220-2-will@kernel.org


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 61135967
Loading
Loading
Loading
Loading
+18 −14
Original line number Diff line number Diff line
@@ -936,20 +936,27 @@ int __pkvm_reclaim_dying_guest_page(pkvm_handle_t handle, u64 gfn)
	return ret;
}

static struct pkvm_hyp_vm *get_pkvm_unref_hyp_vm_locked(pkvm_handle_t handle)
{
	struct pkvm_hyp_vm *hyp_vm;

	hyp_assert_lock_held(&vm_table_lock);

	hyp_vm = get_vm_by_handle(handle);
	if (!hyp_vm || hyp_page_count(hyp_vm))
		return NULL;

	return hyp_vm;
}

int __pkvm_start_teardown_vm(pkvm_handle_t handle)
{
	struct pkvm_hyp_vm *hyp_vm;
	int ret = 0;

	hyp_spin_lock(&vm_table_lock);
	hyp_vm = get_vm_by_handle(handle);
	if (!hyp_vm) {
		ret = -ENOENT;
		goto unlock;
	} else if (WARN_ON(hyp_page_count(hyp_vm))) {
		ret = -EBUSY;
		goto unlock;
	} else if (hyp_vm->kvm.arch.pkvm.is_dying) {
	hyp_vm = get_pkvm_unref_hyp_vm_locked(handle);
	if (!hyp_vm || hyp_vm->kvm.arch.pkvm.is_dying) {
		ret = -EINVAL;
		goto unlock;
	}
@@ -971,12 +978,9 @@ int __pkvm_finalize_teardown_vm(pkvm_handle_t handle)
	int err;

	hyp_spin_lock(&vm_table_lock);
	hyp_vm = get_vm_by_handle(handle);
	if (!hyp_vm) {
		err = -ENOENT;
		goto err_unlock;
	} else if (!hyp_vm->kvm.arch.pkvm.is_dying) {
		err = -EBUSY;
	hyp_vm = get_pkvm_unref_hyp_vm_locked(handle);
	if (!hyp_vm || !hyp_vm->kvm.arch.pkvm.is_dying) {
		err = -EINVAL;
		goto err_unlock;
	}