Commit 15f9017c authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/vgic-ipa-checks into kvmarm-master/next



* kvm-arm64/vgic-ipa-checks:
  : .
  : Add extra checks to prevent ther various GIC regions to land
  : outside of the IPA space (and tests to verify that it works).
  : .
  KVM: arm64: selftests: Add init ITS device test
  KVM: arm64: selftests: Add test for legacy GICv3 REDIST base partially above IPA range
  KVM: arm64: selftests: Add tests for GIC redist/cpuif partially above IPA range
  KVM: arm64: selftests: Add some tests for GICv2 in vgic_init
  KVM: arm64: selftests: Make vgic_init/vm_gic_create version agnostic
  KVM: arm64: selftests: Make vgic_init gic version agnostic
  KVM: arm64: vgic: Drop vgic_check_ioaddr()
  KVM: arm64: vgic-v3: Check ITS region is not above the VM IPA size
  KVM: arm64: vgic-v2: Check cpu interface region is not above the VM IPA size
  KVM: arm64: vgic-v3: Check redist region is not above the VM IPA size
  kvm: arm64: vgic: Introduce vgic_check_iorange

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 3864d17f 3e197f17
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2710,8 +2710,8 @@ static int vgic_its_set_attr(struct kvm_device *dev,
		if (copy_from_user(&addr, uaddr, sizeof(addr)))
			return -EFAULT;

		ret = vgic_check_ioaddr(dev->kvm, &its->vgic_its_base,
					addr, SZ_64K);
		ret = vgic_check_iorange(dev->kvm, its->vgic_its_base,
					 addr, SZ_64K, KVM_VGIC_V3_ITS_SIZE);
		if (ret)
			return ret;

+16 −9
Original line number Diff line number Diff line
@@ -14,17 +14,21 @@

/* common helpers */

int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
		      phys_addr_t addr, phys_addr_t alignment)
int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,
		       phys_addr_t addr, phys_addr_t alignment,
		       phys_addr_t size)
{
	if (addr & ~kvm_phys_mask(kvm))
		return -E2BIG;
	if (!IS_VGIC_ADDR_UNDEF(ioaddr))
		return -EEXIST;

	if (!IS_ALIGNED(addr, alignment))
	if (!IS_ALIGNED(addr, alignment) || !IS_ALIGNED(size, alignment))
		return -EINVAL;

	if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
		return -EEXIST;
	if (addr + size < addr)
		return -EINVAL;

	if (addr & ~kvm_phys_mask(kvm) || addr + size > kvm_phys_size(kvm))
		return -E2BIG;

	return 0;
}
@@ -57,7 +61,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);
@@ -66,16 +70,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;
@@ -140,7 +147,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 {
+4 −2
Original line number Diff line number Diff line
@@ -796,7 +796,9 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index,
	struct vgic_dist *d = &kvm->arch.vgic;
	struct vgic_redist_region *rdreg;
	struct list_head *rd_regions = &d->rd_regions;
	size_t size = count * KVM_VGIC_V3_REDIST_SIZE;
	int nr_vcpus = atomic_read(&kvm->online_vcpus);
	size_t size = count ? count * KVM_VGIC_V3_REDIST_SIZE
			    : nr_vcpus * KVM_VGIC_V3_REDIST_SIZE;
	int ret;

	/* cross the end of memory ? */
@@ -840,7 +842,7 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index,

	rdreg->base = VGIC_ADDR_UNDEF;

	ret = vgic_check_ioaddr(kvm, &rdreg->base, base, SZ_64K);
	ret = vgic_check_iorange(kvm, rdreg->base, base, SZ_64K, size);
	if (ret)
		goto free;

+4 −2
Original line number Diff line number Diff line
@@ -483,8 +483,10 @@ bool vgic_v3_check_base(struct kvm *kvm)
		return false;

	list_for_each_entry(rdreg, &d->rd_regions, list) {
		if (rdreg->base + vgic_v3_rd_region_size(kvm, rdreg) <
			rdreg->base)
		size_t sz = vgic_v3_rd_region_size(kvm, rdreg);

		if (vgic_check_iorange(kvm, VGIC_ADDR_UNDEF,
				       rdreg->base, SZ_64K, sz))
			return false;
	}

+3 −2
Original line number Diff line number Diff line
@@ -172,8 +172,9 @@ void vgic_kick_vcpus(struct kvm *kvm);
void vgic_irq_handle_resampling(struct vgic_irq *irq,
				bool lr_deactivated, bool lr_pending);

int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
		      phys_addr_t addr, phys_addr_t alignment);
int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,
		       phys_addr_t addr, phys_addr_t alignment,
		       phys_addr_t size);

void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
Loading