KVM: arm64: Restrict supported capabilities for protected VMs
authorFuad Tabba <tabba@google.com>
Tue, 23 Apr 2024 15:05:37 +0000 (16:05 +0100)
committerMarc Zyngier <maz@kernel.org>
Wed, 1 May 2024 15:48:14 +0000 (16:48 +0100)
For practical reasons as well as security related ones, not all
capabilities are supported for protected VMs in pKVM.

Add a function that restricts the capabilities for protected VMs.
This behaves as an allow-list to ensure that future capabilities
are checked for compatibility and security before being allowed
for protected VMs.

Signed-off-by: Fuad Tabba <tabba@google.com>
Acked-by: Oliver Upton <oliver.upton@linux.dev>
Link: https://lore.kernel.org/r/20240423150538.2103045-30-tabba@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/arm.c

index 1075b3cf9a3cd9cc3335254d6bbb23a0f9bccbcc..59b17948e7edbfcb3de0a4ef93c8625a28eff4f7 100644 (file)
@@ -69,6 +69,31 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
        return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
 }
 
+/*
+ * This functions as an allow-list of protected VM capabilities.
+ * Features not explicitly allowed by this function are denied.
+ */
+static bool pkvm_ext_allowed(struct kvm *kvm, long ext)
+{
+       switch (ext) {
+       case KVM_CAP_IRQCHIP:
+       case KVM_CAP_ARM_PSCI:
+       case KVM_CAP_ARM_PSCI_0_2:
+       case KVM_CAP_NR_VCPUS:
+       case KVM_CAP_MAX_VCPUS:
+       case KVM_CAP_MAX_VCPU_ID:
+       case KVM_CAP_MSI_DEVID:
+       case KVM_CAP_ARM_VM_IPA_SIZE:
+       case KVM_CAP_ARM_PMU_V3:
+       case KVM_CAP_ARM_SVE:
+       case KVM_CAP_ARM_PTRAUTH_ADDRESS:
+       case KVM_CAP_ARM_PTRAUTH_GENERIC:
+               return true;
+       default:
+               return false;
+       }
+}
+
 int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
                            struct kvm_enable_cap *cap)
 {
@@ -77,6 +102,9 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
        if (cap->flags)
                return -EINVAL;
 
+       if (kvm_vm_is_protected(kvm) && !pkvm_ext_allowed(kvm, cap->cap))
+               return -EINVAL;
+
        switch (cap->cap) {
        case KVM_CAP_ARM_NISV_TO_USER:
                r = 0;
@@ -215,6 +243,10 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
        int r;
+
+       if (kvm && kvm_vm_is_protected(kvm) && !pkvm_ext_allowed(kvm, ext))
+               return 0;
+
        switch (ext) {
        case KVM_CAP_IRQCHIP:
                r = vgic_present;