Alexander Graf 17a802
From: Christoffer Dall <cdall@linaro.org>
Alexander Graf 17a802
Date: Tue, 16 May 2017 12:41:18 +0200
Alexander Graf 17a802
Subject: KVM: arm/arm64: Disallow userspace control of in-kernel IRQ lines
Alexander Graf 17a802
Patch-mainline: v4.13-rc1
Alexander Graf 17a802
Git-commit: cb3f0ad881a6cee39c6a652b4aa4f12f341d98f0
Alexander Graf 17a802
References: bsc#1077761
Alexander Graf 17a802
Alexander Graf 17a802
When injecting an IRQ to the VGIC, you now have to present an owner
Alexander Graf 17a802
token for that IRQ line to show that you are the owner of that line.
Alexander Graf 17a802
Alexander Graf 17a802
IRQ lines driven from userspace or via an irqfd do not have an owner and
Alexander Graf 17a802
will simply pass a NULL pointer.
Alexander Graf 17a802
Alexander Graf 17a802
Also get rid of the unused kvm_vgic_inject_mapped_irq prototype.
Alexander Graf 17a802
Alexander Graf 17a802
Signed-off-by: Christoffer Dall <cdall@linaro.org>
Alexander Graf 17a802
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Alexander Graf 17a802
Acked-by: Alexander Graf <agraf@suse.de>
Alexander Graf 17a802
---
Alexander Graf 17a802
 include/kvm/arm_vgic.h         |    4 +---
Alexander Graf 17a802
 virt/kvm/arm/arch_timer.c      |    3 ++-
Alexander Graf 17a802
 virt/kvm/arm/arm.c             |    4 ++--
Alexander Graf 17a802
 virt/kvm/arm/pmu.c             |    3 ++-
Alexander Graf 17a802
 virt/kvm/arm/vgic/vgic-irqfd.c |    2 +-
Alexander Graf 17a802
 virt/kvm/arm/vgic/vgic.c       |   15 +++++++++++----
Alexander Graf 17a802
 6 files changed, 19 insertions(+), 12 deletions(-)
Alexander Graf 17a802
Alexander Graf 17a802
--- a/include/kvm/arm_vgic.h
Alexander Graf 17a802
+++ b/include/kvm/arm_vgic.h
Alexander Graf 17a802
@@ -303,9 +303,7 @@
Alexander Graf 17a802
 void kvm_vgic_init_cpu_hardware(void);
Alexander Graf 17a802
 
Alexander Graf 17a802
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
Alexander Graf 17a802
-			bool level);
Alexander Graf 17a802
-int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
Alexander Graf 17a802
-			       bool level);
Alexander Graf 17a802
+			bool level, void *owner);
Alexander Graf 17a802
 int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
Alexander Graf 17a802
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
Alexander Graf 17a802
 bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
Alexander Graf 17a802
--- a/virt/kvm/arm/arch_timer.c
Alexander Graf 17a802
+++ b/virt/kvm/arm/arch_timer.c
Alexander Graf 17a802
@@ -226,7 +226,8 @@
Alexander Graf 17a802
 	if (likely(irqchip_in_kernel(vcpu->kvm))) {
Alexander Graf 17a802
 		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
Alexander Graf 17a802
 					  timer_ctx->irq.irq,
Alexander Graf 17a802
-					  timer_ctx->irq.level);
Alexander Graf 17a802
+					  timer_ctx->irq.level,
Alexander Graf 17a802
+					  timer_ctx);
Alexander Graf 17a802
 		WARN_ON(ret);
Alexander Graf 17a802
 	}
Alexander Graf 17a802
 }
Alexander Graf 17a802
--- a/virt/kvm/arm/arm.c
Alexander Graf 17a802
+++ b/virt/kvm/arm/arm.c
Alexander Graf 17a802
@@ -832,7 +832,7 @@
Alexander Graf 17a802
 		if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS)
Alexander Graf 17a802
 			return -EINVAL;
Alexander Graf 17a802
 
Alexander Graf 17a802
-		return kvm_vgic_inject_irq(kvm, vcpu->vcpu_id, irq_num, level);
Alexander Graf 17a802
+		return kvm_vgic_inject_irq(kvm, vcpu->vcpu_id, irq_num, level, NULL);
Alexander Graf 17a802
 	case KVM_ARM_IRQ_TYPE_SPI:
Alexander Graf 17a802
 		if (!irqchip_in_kernel(kvm))
Alexander Graf 17a802
 			return -ENXIO;
Alexander Graf 17a802
@@ -840,7 +840,7 @@
Alexander Graf 17a802
 		if (irq_num < VGIC_NR_PRIVATE_IRQS)
Alexander Graf 17a802
 			return -EINVAL;
Alexander Graf 17a802
 
Alexander Graf 17a802
-		return kvm_vgic_inject_irq(kvm, 0, irq_num, level);
Alexander Graf 17a802
+		return kvm_vgic_inject_irq(kvm, 0, irq_num, level, NULL);
Alexander Graf 17a802
 	}
Alexander Graf 17a802
 
Alexander Graf 17a802
 	return -EINVAL;
Alexander Graf 17a802
--- a/virt/kvm/arm/pmu.c
Alexander Graf 17a802
+++ b/virt/kvm/arm/pmu.c
Alexander Graf 17a802
@@ -215,7 +215,8 @@
Alexander Graf 17a802
 
Alexander Graf 17a802
 	if (likely(irqchip_in_kernel(vcpu->kvm))) {
Alexander Graf 17a802
 		int ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
Alexander Graf 17a802
-					      pmu->irq_num, overflow);
Alexander Graf 17a802
+					      pmu->irq_num, overflow,
Alexander Graf 17a802
+					      &vcpu->arch.pmu);
Alexander Graf 17a802
 		WARN_ON(ret);
Alexander Graf 17a802
 	}
Alexander Graf 17a802
 }
Alexander Graf 17a802
--- a/virt/kvm/arm/vgic/vgic-irqfd.c
Alexander Graf 17a802
+++ b/virt/kvm/arm/vgic/vgic-irqfd.c
Alexander Graf 17a802
@@ -34,7 +34,7 @@
Alexander Graf 17a802
 
Alexander Graf 17a802
 	if (!vgic_valid_spi(kvm, spi_id))
Alexander Graf 17a802
 		return -EINVAL;
Alexander Graf 17a802
-	return kvm_vgic_inject_irq(kvm, 0, spi_id, level);
Alexander Graf 17a802
+	return kvm_vgic_inject_irq(kvm, 0, spi_id, level, NULL);
Alexander Graf 17a802
 }
Alexander Graf 17a802
 
Alexander Graf 17a802
 /**
Alexander Graf 17a802
--- a/virt/kvm/arm/vgic/vgic.c
Alexander Graf 17a802
+++ b/virt/kvm/arm/vgic/vgic.c
Alexander Graf 17a802
@@ -235,10 +235,14 @@
Alexander Graf 17a802
 
Alexander Graf 17a802
 /*
Alexander Graf 17a802
  * Only valid injection if changing level for level-triggered IRQs or for a
Alexander Graf 17a802
- * rising edge.
Alexander Graf 17a802
+ * rising edge, and in-kernel connected IRQ lines can only be controlled by
Alexander Graf 17a802
+ * their owner.
Alexander Graf 17a802
  */
Alexander Graf 17a802
-static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
Alexander Graf 17a802
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *owner)
Alexander Graf 17a802
 {
Alexander Graf 17a802
+	if (irq->owner != owner)
Alexander Graf 17a802
+		return false;
Alexander Graf 17a802
+
Alexander Graf 17a802
 	switch (irq->config) {
Alexander Graf 17a802
 	case VGIC_CONFIG_LEVEL:
Alexander Graf 17a802
 		return irq->line_level != level;
Alexander Graf 17a802
@@ -350,13 +354,16 @@
Alexander Graf 17a802
  *			      false: to ignore the call
Alexander Graf 17a802
  *	     Level-sensitive  true:  raise the input signal
Alexander Graf 17a802
  *			      false: lower the input signal
Alexander Graf 17a802
+ * @owner:   The opaque pointer to the owner of the IRQ being raised to verify
Alexander Graf 17a802
+ *           that the caller is allowed to inject this IRQ.  Userspace
Alexander Graf 17a802
+ *           injections will have owner == NULL.
Alexander Graf 17a802
  *
Alexander Graf 17a802
  * The VGIC is not concerned with devices being active-LOW or active-HIGH for
Alexander Graf 17a802
  * level-sensitive interrupts.  You can think of the level parameter as 1
Alexander Graf 17a802
  * being HIGH and 0 being LOW and all devices being active-HIGH.
Alexander Graf 17a802
  */
Alexander Graf 17a802
 int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
Alexander Graf 17a802
-			bool level)
Alexander Graf 17a802
+			bool level, void *owner)
Alexander Graf 17a802
 {
Alexander Graf 17a802
 	struct kvm_vcpu *vcpu;
Alexander Graf 17a802
 	struct vgic_irq *irq;
Alexander Graf 17a802
@@ -378,7 +385,7 @@
Alexander Graf 17a802
 
Alexander Graf 17a802
 	spin_lock(&irq->irq_lock);
Alexander Graf 17a802
 
Alexander Graf 17a802
-	if (!vgic_validate_injection(irq, level)) {
Alexander Graf 17a802
+	if (!vgic_validate_injection(irq, level, owner)) {
Alexander Graf 17a802
 		/* Nothing to see here, move along... */
Alexander Graf 17a802
 		spin_unlock(&irq->irq_lock);
Alexander Graf 17a802
 		vgic_put_irq(kvm, irq);