From: Suzuki K Poulose Once the Realm is created, prevent any changes to guest_memfd backed memslots, as the private memory is provided by slots backed by gmem. This will also be validated when we handle a fault for Realm Stage2 (in a later commit). Require Realm memslots to lie in the lower half of the IPA space, as the upper, shared half aliases the lower, protected half. A rejected deletion can already have invalidated the memslot before the prepare hook rejects it. Keep private mappings intact in this case. Additionally, similar to pKVM, we do not support dirty logging or read-only memslots. Signed-off-by: Suzuki K Poulose Signed-off-by: Steven Price --- Changes since v1: - Preserve private mappings if KVM invalidates a Realm guest_memfd slot before the prepare hook rejects its deletion. --- arch/arm64/include/asm/kvm_host.h | 2 ++ arch/arm64/kvm/mmu.c | 37 +++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index d672d87ffe62..a82b18a3e4e5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1612,6 +1612,8 @@ struct kvm *kvm_arch_alloc_vm(void); #define kvm_vm_hyp_is_distrusting(kvm) ((kvm)->arch.vm_flavor >= __VM_DISTRUSTING_HYP) +#define kvm_arch_has_private_mem(kvm) kvm_vm_is_realm(kvm) + #define kvm_has_mte(kvm) \ (system_supports_mte() && \ test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &(kvm)->arch.flags)) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 8c29ed204d61..e550360fc94d 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -2858,17 +2858,32 @@ int kvm_arch_validate_memory_region(struct kvm *kvm, { lockdep_assert_held(&kvm->slots_lock); - if (kvm_vm_is_protected(kvm)) { + if (kvm_vm_is_protected(kvm) && new && + (new->flags & (KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_READONLY))) + return -EPERM; + + switch (kvm->arch.vm_flavor) { + case VM_PROTECTED_PKVM: /* Cannot modify memslots once a pVM has run. */ if (pkvm_hyp_vm_is_created(kvm) && - (change == KVM_MR_DELETE || change == KVM_MR_MOVE)) { + (change == KVM_MR_DELETE || change == KVM_MR_MOVE)) return -EPERM; - } + break; + case VM_REALM: + /* + * Once the Realm is created, we cannot modify any slots that + * could be providing private memory. i.e., guest_memfd backed + * slots. + * TODO: Handle trusted device private memory slots + */ + if (!kvm_realm_is_created(kvm)) + break; - if (new && - new->flags & (KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_READONLY)) { + if (kvm_slot_has_gmem(old) || kvm_slot_has_gmem(new)) return -EPERM; - } + break; + default: + break; } return 0; @@ -2880,6 +2895,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, enum kvm_mr_change change) { hva_t hva, reg_end; + gfn_t ipa_limit; int ret = 0; if (change != KVM_MR_CREATE && change != KVM_MR_MOVE && @@ -2887,10 +2903,13 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, return 0; /* - * Prevent userspace from creating a memory region outside of the IPA - * space addressable by the KVM guest IPA space. + * Realm shared IPAs alias the corresponding private IPAs, so memslots + * must reside entirely in the canonical lower half of the IPA space. */ - if ((new->base_gfn + new->npages) > (kvm_phys_size(&kvm->arch.mmu) >> PAGE_SHIFT)) + ipa_limit = kvm_phys_size(&kvm->arch.mmu) >> PAGE_SHIFT; + if (kvm_vm_is_realm(kvm)) + ipa_limit >>= 1; + if (new->base_gfn + new->npages > ipa_limit) return -EFAULT; /* -- 2.43.0