[PATCH v4 7/8] KVM: arm64: Check whether a VM IOCTL is allowed in pKVM
Fuad Tabba
tabba at google.com
Wed Nov 12 01:20:50 PST 2025
Certain VM IOCTLs are tied to specific VM features. Since pKVM does not
support all features, restrict which IOCTLs are allowed depending on
whether the associated feature is supported.
Use the existing VM capability check as the source of truth to whether
an IOCTL is allowed for a particular VM by mapping the IOCTLs with their
associated capabilities.
Suggested-by: Oliver Upton <oupton at kernel.org>
Signed-off-by: Fuad Tabba <tabba at google.com>
---
arch/arm64/include/asm/kvm_pkvm.h | 29 +++++++++++++++++++++++++++++
arch/arm64/kvm/arm.c | 3 +++
2 files changed, 32 insertions(+)
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 5b564576160d..7a418ea276d1 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -51,6 +51,35 @@ static inline bool kvm_pkvm_ext_allowed(struct kvm *kvm, long ext)
}
}
+/*
+ * Check whether the KVM VM IOCTL is allowed in pKVM.
+ *
+ * Certain features are allowed only for non-protected VMs in pKVM, which is why
+ * this takes the VM (kvm) as a parameter.
+ */
+static inline bool kvm_pkvm_ioctl_allowed(struct kvm *kvm, unsigned int ioctl)
+{
+ switch (ioctl) {
+ case KVM_CREATE_IRQCHIP:
+ return kvm_pkvm_ext_allowed(kvm, KVM_CAP_IRQCHIP);
+ case KVM_ARM_SET_DEVICE_ADDR:
+ return kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SET_DEVICE_ADDR);
+ case KVM_ARM_MTE_COPY_TAGS:
+ return kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE);
+ case KVM_ARM_SET_COUNTER_OFFSET:
+ return kvm_pkvm_ext_allowed(kvm, KVM_CAP_COUNTER_OFFSET);
+ case KVM_HAS_DEVICE_ATTR:
+ case KVM_SET_DEVICE_ATTR:
+ case KVM_GET_DEVICE_ATTR:
+ return kvm_pkvm_ext_allowed(kvm, KVM_CAP_DEVICE_CTRL) ||
+ kvm_pkvm_ext_allowed(kvm, KVM_CAP_VM_ATTRIBUTES);
+ case KVM_ARM_GET_REG_WRITABLE_MASKS:
+ return kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES);
+ default:
+ return true;
+ }
+}
+
extern struct memblock_region kvm_nvhe_sym(hyp_memory)[];
extern unsigned int kvm_nvhe_sym(hyp_memblock_nr);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 10d853f2722e..020cadd811a3 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1879,6 +1879,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
void __user *argp = (void __user *)arg;
struct kvm_device_attr attr;
+ if (is_protected_kvm_enabled() && !kvm_pkvm_ioctl_allowed(kvm, ioctl))
+ return -EINVAL;
+
switch (ioctl) {
case KVM_CREATE_IRQCHIP: {
int ret;
--
2.51.2.1041.gc1ab5b90ca-goog
More information about the linux-arm-kernel
mailing list