mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
ANDROID: KVM: arm64: Pin host structs for pVMs
In nVHE protected mode the hypervisor sometime needs to read or write to host-provided data-structures, such as vcpu structs or the kvm struct. To ensure that the hypervisor can't be tricked by the host into writing to pages it doesn't own, let's pin the host pages containing those data structures during the shadow vm creation. This will ensure those pages remain in a host-shared state for the lifetime of the VM. Signed-off-by: Quentin Perret <qperret@google.com> Bug: 209580772 Change-Id: Id11bd6a86754b6a3e0c504b06940df310641357d Signed-off-by: Will Deacon <willdeacon@google.com>
This commit is contained in:
committed by
Will Deacon
parent
7b2e541a63
commit
ab2c31fe1d
@@ -312,10 +312,21 @@ static void copy_features(struct kvm_vcpu *shadow_vcpu, struct kvm_vcpu *host_vc
|
||||
allowed_features, KVM_VCPU_MAX_FEATURES);
|
||||
}
|
||||
|
||||
static void init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, int nr_vcpus)
|
||||
static void unpin_host_vcpus(struct kvm_shadow_vm *vm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vm->created_vcpus; i++) {
|
||||
struct kvm_vcpu *vcpu = vm->vcpus[i]->arch.pkvm.host_vcpu;
|
||||
hyp_unpin_shared_mem(vcpu, vcpu + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, int nr_vcpus)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* TODO: initialize the protected MMU. For now, use the host's. */
|
||||
vm->mmu = &kvm->arch.mmu;
|
||||
vm->host_kvm = kvm;
|
||||
@@ -326,6 +337,12 @@ static void init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, int n
|
||||
struct shadow_vcpu_state *shadow_state = &vm->shadow_vcpus[i];
|
||||
struct kvm_vcpu *shadow_vcpu = &shadow_state->vcpu;
|
||||
|
||||
ret = hyp_pin_shared_mem(host_vcpu, host_vcpu + 1);
|
||||
if (ret)
|
||||
return -EBUSY;
|
||||
|
||||
vm->created_vcpus++;
|
||||
|
||||
shadow_vcpu->kvm = kvm;
|
||||
shadow_vcpu->vcpu_id = host_vcpu->vcpu_id;
|
||||
shadow_vcpu->vcpu_idx = i;
|
||||
@@ -347,9 +364,9 @@ static void init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm, int n
|
||||
shadow_vcpu->arch.pkvm.shadow_handle = vm->shadow_handle;
|
||||
shadow_vcpu->arch.pkvm.host_vcpu = host_vcpu;
|
||||
shadow_vcpu->arch.pkvm.shadow_vm = vm;
|
||||
|
||||
vm->created_vcpus++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool exists_shadow(struct kvm *host_kvm)
|
||||
@@ -486,6 +503,10 @@ int __pkvm_init_shadow(struct kvm *kvm,
|
||||
|
||||
kvm = kern_hyp_va(kvm);
|
||||
|
||||
ret = hyp_pin_shared_mem(kvm, kvm + 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Ensure the host has donated enough memory for the shadow structs. */
|
||||
nr_vcpus = kvm->created_vcpus;
|
||||
ret = check_shadow_size(nr_vcpus, shadow_size);
|
||||
@@ -504,16 +525,20 @@ int __pkvm_init_shadow(struct kvm *kvm,
|
||||
if (ret < 0)
|
||||
goto err_clear_shadow;
|
||||
|
||||
init_shadow_structs(kvm, vm, nr_vcpus);
|
||||
ret = init_shadow_structs(kvm, vm, nr_vcpus);
|
||||
if (ret < 0)
|
||||
goto err_clear_shadow;
|
||||
|
||||
return vm->shadow_handle;
|
||||
|
||||
err_clear_shadow:
|
||||
unpin_host_vcpus(vm);
|
||||
/* Clear the donated shadow memory on failure to avoid data leaks. */
|
||||
memset(vm, 0, shadow_size);
|
||||
WARN_ON(__pkvm_hyp_donate_host(pfn, nr_pages));
|
||||
|
||||
err:
|
||||
hyp_unpin_shared_mem(kvm, kvm + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -536,6 +561,8 @@ int __pkvm_teardown_shadow(struct kvm *kvm)
|
||||
|
||||
shadow_size = vm->shadow_area_size;
|
||||
|
||||
unpin_host_vcpus(vm);
|
||||
hyp_unpin_shared_mem(vm->host_kvm, vm->host_kvm + 1);
|
||||
remove_shadow_table(shadow_handle);
|
||||
|
||||
/* Clear the shadow memory since hyp is releasing it back to host. */
|
||||
|
||||
Reference in New Issue
Block a user