diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2015-07-24 06:30:43 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2015-08-12 06:28:26 -0400 |
commit | 773299a570725d1f253d6046cd6475209b0dcd55 (patch) | |
tree | a9d54841a4a92de76dad049bea4db351e7d35f5a /virt/kvm/arm | |
parent | 6e84e0e0677281b4e7fc634c7e9d085fbcf41b10 (diff) |
KVM: arm/arm64: vgic: Prevent userspace injection of a mapped interrupt
Virtual interrupts mapped to a HW interrupt should only be triggered
from inside the kernel. Otherwise, you could end up confusing the
kernel (and the GIC's) state machine.
Rearrange the injection path so that kvm_vgic_inject_irq is
used for non-mapped interrupts, and kvm_vgic_inject_mapped_irq is
used for mapped interrupts. The latter should only be called from
inside the kernel (timer, irqfd).
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt/kvm/arm')
-rw-r--r-- | virt/kvm/arm/vgic.c | 103 |
1 files changed, 70 insertions, 33 deletions
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index b553a8fa6430..9eb489a2c94c 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c | |||
@@ -1555,7 +1555,8 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level) | |||
1555 | } | 1555 | } |
1556 | 1556 | ||
1557 | static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, | 1557 | static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, |
1558 | unsigned int irq_num, bool level) | 1558 | struct irq_phys_map *map, |
1559 | unsigned int irq_num, bool level) | ||
1559 | { | 1560 | { |
1560 | struct vgic_dist *dist = &kvm->arch.vgic; | 1561 | struct vgic_dist *dist = &kvm->arch.vgic; |
1561 | struct kvm_vcpu *vcpu; | 1562 | struct kvm_vcpu *vcpu; |
@@ -1563,6 +1564,9 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, | |||
1563 | int enabled; | 1564 | int enabled; |
1564 | bool ret = true, can_inject = true; | 1565 | bool ret = true, can_inject = true; |
1565 | 1566 | ||
1567 | if (irq_num >= min(kvm->arch.vgic.nr_irqs, 1020)) | ||
1568 | return -EINVAL; | ||
1569 | |||
1566 | spin_lock(&dist->lock); | 1570 | spin_lock(&dist->lock); |
1567 | 1571 | ||
1568 | vcpu = kvm_get_vcpu(kvm, cpuid); | 1572 | vcpu = kvm_get_vcpu(kvm, cpuid); |
@@ -1625,18 +1629,46 @@ static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, | |||
1625 | out: | 1629 | out: |
1626 | spin_unlock(&dist->lock); | 1630 | spin_unlock(&dist->lock); |
1627 | 1631 | ||
1628 | return ret ? cpuid : -EINVAL; | 1632 | if (ret) { |
1633 | /* kick the specified vcpu */ | ||
1634 | kvm_vcpu_kick(kvm_get_vcpu(kvm, cpuid)); | ||
1635 | } | ||
1636 | |||
1637 | return 0; | ||
1638 | } | ||
1639 | |||
1640 | static int vgic_lazy_init(struct kvm *kvm) | ||
1641 | { | ||
1642 | int ret = 0; | ||
1643 | |||
1644 | if (unlikely(!vgic_initialized(kvm))) { | ||
1645 | /* | ||
1646 | * We only provide the automatic initialization of the VGIC | ||
1647 | * for the legacy case of a GICv2. Any other type must | ||
1648 | * be explicitly initialized once setup with the respective | ||
1649 | * KVM device call. | ||
1650 | */ | ||
1651 | if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2) | ||
1652 | return -EBUSY; | ||
1653 | |||
1654 | mutex_lock(&kvm->lock); | ||
1655 | ret = vgic_init(kvm); | ||
1656 | mutex_unlock(&kvm->lock); | ||
1657 | } | ||
1658 | |||
1659 | return ret; | ||
1629 | } | 1660 | } |
1630 | 1661 | ||
1631 | /** | 1662 | /** |
1632 | * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic | 1663 | * kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic |
1633 | * @kvm: The VM structure pointer | 1664 | * @kvm: The VM structure pointer |
1634 | * @cpuid: The CPU for PPIs | 1665 | * @cpuid: The CPU for PPIs |
1635 | * @irq_num: The IRQ number that is assigned to the device | 1666 | * @irq_num: The IRQ number that is assigned to the device. This IRQ |
1667 | * must not be mapped to a HW interrupt. | ||
1636 | * @level: Edge-triggered: true: to trigger the interrupt | 1668 | * @level: Edge-triggered: true: to trigger the interrupt |
1637 | * false: to ignore the call | 1669 | * false: to ignore the call |
1638 | * Level-sensitive true: activates an interrupt | 1670 | * Level-sensitive true: raise the input signal |
1639 | * false: deactivates an interrupt | 1671 | * false: lower the input signal |
1640 | * | 1672 | * |
1641 | * The GIC is not concerned with devices being active-LOW or active-HIGH for | 1673 | * The GIC is not concerned with devices being active-LOW or active-HIGH for |
1642 | * level-sensitive interrupts. You can think of the level parameter as 1 | 1674 | * level-sensitive interrupts. You can think of the level parameter as 1 |
@@ -1645,39 +1677,44 @@ out: | |||
1645 | int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, | 1677 | int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, |
1646 | bool level) | 1678 | bool level) |
1647 | { | 1679 | { |
1648 | int ret = 0; | 1680 | struct irq_phys_map *map; |
1649 | int vcpu_id; | 1681 | int ret; |
1650 | |||
1651 | if (unlikely(!vgic_initialized(kvm))) { | ||
1652 | /* | ||
1653 | * We only provide the automatic initialization of the VGIC | ||
1654 | * for the legacy case of a GICv2. Any other type must | ||
1655 | * be explicitly initialized once setup with the respective | ||
1656 | * KVM device call. | ||
1657 | */ | ||
1658 | if (kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V2) { | ||
1659 | ret = -EBUSY; | ||
1660 | goto out; | ||
1661 | } | ||
1662 | mutex_lock(&kvm->lock); | ||
1663 | ret = vgic_init(kvm); | ||
1664 | mutex_unlock(&kvm->lock); | ||
1665 | 1682 | ||
1666 | if (ret) | 1683 | ret = vgic_lazy_init(kvm); |
1667 | goto out; | 1684 | if (ret) |
1668 | } | 1685 | return ret; |
1669 | 1686 | ||
1670 | if (irq_num >= min(kvm->arch.vgic.nr_irqs, 1020)) | 1687 | map = vgic_irq_map_search(kvm_get_vcpu(kvm, cpuid), irq_num); |
1688 | if (map) | ||
1671 | return -EINVAL; | 1689 | return -EINVAL; |
1672 | 1690 | ||
1673 | vcpu_id = vgic_update_irq_pending(kvm, cpuid, irq_num, level); | 1691 | return vgic_update_irq_pending(kvm, cpuid, NULL, irq_num, level); |
1674 | if (vcpu_id >= 0) { | 1692 | } |
1675 | /* kick the specified vcpu */ | ||
1676 | kvm_vcpu_kick(kvm_get_vcpu(kvm, vcpu_id)); | ||
1677 | } | ||
1678 | 1693 | ||
1679 | out: | 1694 | /** |
1680 | return ret; | 1695 | * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic |
1696 | * @kvm: The VM structure pointer | ||
1697 | * @cpuid: The CPU for PPIs | ||
1698 | * @map: Pointer to a irq_phys_map structure describing the mapping | ||
1699 | * @level: Edge-triggered: true: to trigger the interrupt | ||
1700 | * false: to ignore the call | ||
1701 | * Level-sensitive true: raise the input signal | ||
1702 | * false: lower the input signal | ||
1703 | * | ||
1704 | * The GIC is not concerned with devices being active-LOW or active-HIGH for | ||
1705 | * level-sensitive interrupts. You can think of the level parameter as 1 | ||
1706 | * being HIGH and 0 being LOW and all devices being active-HIGH. | ||
1707 | */ | ||
1708 | int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, | ||
1709 | struct irq_phys_map *map, bool level) | ||
1710 | { | ||
1711 | int ret; | ||
1712 | |||
1713 | ret = vgic_lazy_init(kvm); | ||
1714 | if (ret) | ||
1715 | return ret; | ||
1716 | |||
1717 | return vgic_update_irq_pending(kvm, cpuid, map, map->virt_irq, level); | ||
1681 | } | 1718 | } |
1682 | 1719 | ||
1683 | static irqreturn_t vgic_maintenance_handler(int irq, void *data) | 1720 | static irqreturn_t vgic_maintenance_handler(int irq, void *data) |