ANDROID: KVM: arm64: iommu: Add owner to domains
Add an owner to each domain either host or a VM which is set at alloc time, and all other IOMMU operations would be allowed only from the domain owner. The new vm member is protected by kvm_iommu_domain_lock while set/cleared in alloc/free, and the check is done only after the domain refcount is elevated to avoid racing with alloc. Bug: 357781595 Bug: 348382247 Bug: 236685427 Change-Id: Ie23379d958922368ec3be2127ba90393709a77bb Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
8a9430e18b
commit
540b4b9ce3
@@ -219,14 +219,29 @@ handle_to_domain(pkvm_handle_t domain_id)
|
||||
static int domain_get(struct kvm_hyp_iommu_domain *domain)
|
||||
{
|
||||
int old = atomic_fetch_inc_acquire(&domain->refs);
|
||||
struct pkvm_hyp_vcpu *hyp_vcpu = __get_vcpu();
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!old || (old + 1 < 0));
|
||||
return 0;
|
||||
|
||||
/* check done after refcount is elevated to avoid race with alloc_domain */
|
||||
if (!hyp_vcpu && domain->vm)
|
||||
ret = -EPERM;
|
||||
if (hyp_vcpu && (domain->vm != pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu)))
|
||||
ret = -EPERM;
|
||||
|
||||
if (ret)
|
||||
atomic_dec_return_release(&domain->refs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void domain_put(struct kvm_hyp_iommu_domain *domain)
|
||||
{
|
||||
struct pkvm_hyp_vcpu *hyp_vcpu = __get_vcpu();
|
||||
|
||||
BUG_ON(!atomic_dec_return_release(&domain->refs));
|
||||
WARN_ON(!hyp_vcpu && domain->vm);
|
||||
WARN_ON(hyp_vcpu && (domain->vm != pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu)));
|
||||
}
|
||||
|
||||
static int kvm_iommu_init_atomic_pool(struct kvm_hyp_memcache *atomic_mc)
|
||||
@@ -285,6 +300,8 @@ int kvm_iommu_alloc_domain(pkvm_handle_t domain_id, int type)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct kvm_hyp_iommu_domain *domain;
|
||||
struct pkvm_hyp_vcpu *hyp_vcpu = __get_vcpu();
|
||||
struct pkvm_hyp_vm *vm;
|
||||
|
||||
domain = handle_to_domain(domain_id);
|
||||
if (!domain)
|
||||
@@ -299,6 +316,10 @@ int kvm_iommu_alloc_domain(pkvm_handle_t domain_id, int type)
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
if (hyp_vcpu) {
|
||||
vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
domain->vm = vm;
|
||||
}
|
||||
atomic_set_release(&domain->refs, 1);
|
||||
out_unlock:
|
||||
hyp_spin_unlock(&kvm_iommu_domain_lock);
|
||||
@@ -309,13 +330,18 @@ int kvm_iommu_free_domain(pkvm_handle_t domain_id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct kvm_hyp_iommu_domain *domain;
|
||||
struct pkvm_hyp_vcpu *hyp_vcpu = __get_vcpu();
|
||||
struct pkvm_hyp_vm *vm = NULL;
|
||||
|
||||
domain = handle_to_domain(domain_id);
|
||||
if (!domain)
|
||||
return -EINVAL;
|
||||
|
||||
hyp_spin_lock(&kvm_iommu_domain_lock);
|
||||
if (WARN_ON(atomic_cmpxchg_acquire(&domain->refs, 1, 0) != 1)) {
|
||||
if (hyp_vcpu)
|
||||
vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
|
||||
if (WARN_ON(atomic_cmpxchg_acquire(&domain->refs, 1, 0) != 1) || domain->vm != vm) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ struct kvm_hyp_iommu_domain {
|
||||
atomic_t refs;
|
||||
pkvm_handle_t domain_id;
|
||||
void *priv;
|
||||
void *vm;
|
||||
ANDROID_KABI_RESERVE(1);
|
||||
ANDROID_KABI_RESERVE(2);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user