KVM: arm64: vgic-v2: Check cpu interface region is not above the VM IPA size
authorRicardo Koller <ricarkol@google.com>
Tue, 5 Oct 2021 01:19:13 +0000 (18:19 -0700)
committerMarc Zyngier <maz@kernel.org>
Mon, 11 Oct 2021 08:31:41 +0000 (09:31 +0100)
Verify that the GICv2 CPU interface does not extend beyond the
VM-specified IPA range (phys_size).

  base + size > phys_size AND base < phys_size

Add the missing check into kvm_vgic_addr() which is called when setting
the region. This patch also enables some superfluous checks for the
distributor (vgic_check_ioaddr was enough as alignment == size for the
distributors).

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Ricardo Koller <ricarkol@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20211005011921.437353-4-ricarkol@google.com
arch/arm64/kvm/vgic/vgic-kvm-device.c

index cc0ad227b38013766726769cc9c7986a07a94959..08ae34b1a9861b757842bee8d097222c517a67f7 100644 (file)
@@ -79,7 +79,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
 {
        int r = 0;
        struct vgic_dist *vgic = &kvm->arch.vgic;
-       phys_addr_t *addr_ptr, alignment;
+       phys_addr_t *addr_ptr, alignment, size;
        u64 undef_value = VGIC_ADDR_UNDEF;
 
        mutex_lock(&kvm->lock);
@@ -88,16 +88,19 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
                r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
                addr_ptr = &vgic->vgic_dist_base;
                alignment = SZ_4K;
+               size = KVM_VGIC_V2_DIST_SIZE;
                break;
        case KVM_VGIC_V2_ADDR_TYPE_CPU:
                r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
                addr_ptr = &vgic->vgic_cpu_base;
                alignment = SZ_4K;
+               size = KVM_VGIC_V2_CPU_SIZE;
                break;
        case KVM_VGIC_V3_ADDR_TYPE_DIST:
                r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
                addr_ptr = &vgic->vgic_dist_base;
                alignment = SZ_64K;
+               size = KVM_VGIC_V3_DIST_SIZE;
                break;
        case KVM_VGIC_V3_ADDR_TYPE_REDIST: {
                struct vgic_redist_region *rdreg;
@@ -162,7 +165,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
                goto out;
 
        if (write) {
-               r = vgic_check_ioaddr(kvm, addr_ptr, *addr, alignment);
+               r = vgic_check_iorange(kvm, *addr_ptr, *addr, alignment, size);
                if (!r)
                        *addr_ptr = *addr;
        } else {