Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c6c631f authored by Jing Zhang's avatar Jing Zhang Committed by Greg Kroah-Hartman
Browse files

KVM: arm64: vgic-its: Add a data length check in vgic_its_save_*



commit 7fe28d7e68f92cc3d0668b8f2fbdf5c303ac3022 upstream.

In all the vgic_its_save_*() functinos, they do not check whether
the data length is 8 bytes before calling vgic_write_guest_lock.
This patch adds the check. To prevent the kernel from being blown up
when the fault occurs, KVM_BUG_ON() is used. And the other BUG_ON()s
are replaced together.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarKunkun Jiang <jiangkunkun@huawei.com>
[Jing: Update with the new entry read/write helpers]
Signed-off-by: default avatarJing Zhang <jingzhangos@google.com>
Link: https://lore.kernel.org/r/20241107214137.428439-4-jingzhangos@google.com


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c0978ecb
Loading
Loading
Loading
Loading
+8 −12
Original line number Diff line number Diff line
@@ -2134,7 +2134,6 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
			      struct its_ite *ite, gpa_t gpa, int ite_esz)
{
	struct kvm *kvm = its->dev->kvm;
	u32 next_offset;
	u64 val;

@@ -2143,7 +2142,8 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
		ite->collection->collection_id;
	val = cpu_to_le64(val);
	return kvm_write_guest_lock(kvm, gpa, &val, ite_esz);

	return vgic_its_write_entry_lock(its, gpa, val, ite_esz);
}

/**
@@ -2279,7 +2279,6 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
			     gpa_t ptr, int dte_esz)
{
	struct kvm *kvm = its->dev->kvm;
	u64 val, itt_addr_field;
	u32 next_offset;

@@ -2290,7 +2289,8 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
		(dev->num_eventid_bits - 1));
	val = cpu_to_le64(val);
	return kvm_write_guest_lock(kvm, ptr, &val, dte_esz);

	return vgic_its_write_entry_lock(its, ptr, val, dte_esz);
}

/**
@@ -2470,7 +2470,8 @@ static int vgic_its_save_cte(struct vgic_its *its,
	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
	       collection->collection_id);
	val = cpu_to_le64(val);
	return kvm_write_guest_lock(its->dev->kvm, gpa, &val, esz);

	return vgic_its_write_entry_lock(its, gpa, val, esz);
}

static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
@@ -2481,8 +2482,7 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
	u64 val;
	int ret;

	BUG_ON(esz > sizeof(val));
	ret = kvm_read_guest_lock(kvm, gpa, &val, esz);
	ret = vgic_its_read_entry_lock(its, gpa, &val, esz);
	if (ret)
		return ret;
	val = le64_to_cpu(val);
@@ -2516,7 +2516,6 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
	u64 baser = its->baser_coll_table;
	gpa_t gpa = GITS_BASER_ADDR_48_to_52(baser);
	struct its_collection *collection;
	u64 val;
	size_t max_size, filled = 0;
	int ret, cte_esz = abi->cte_esz;

@@ -2540,10 +2539,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
	 * table is not fully filled, add a last dummy element
	 * with valid bit unset
	 */
	val = 0;
	BUG_ON(cte_esz > sizeof(val));
	ret = kvm_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
	return ret;
	return vgic_its_write_entry_lock(its, gpa, 0, cte_esz);
}

/**
+24 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#define __KVM_ARM_VGIC_NEW_H__

#include <linux/irqchip/arm-gic-common.h>
#include <asm/kvm_mmu.h>

#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
#define IMPLEMENTER_ARM		0x43b
@@ -126,6 +127,29 @@ static inline bool vgic_irq_is_multi_sgi(struct vgic_irq *irq)
	return vgic_irq_get_lr_count(irq) > 1;
}

static inline int vgic_its_read_entry_lock(struct vgic_its *its, gpa_t eaddr,
					   u64 *eval, unsigned long esize)
{
	struct kvm *kvm = its->dev->kvm;

	if (KVM_BUG_ON(esize != sizeof(*eval), kvm))
		return -EINVAL;

	return kvm_read_guest_lock(kvm, eaddr, eval, esize);

}

static inline int vgic_its_write_entry_lock(struct vgic_its *its, gpa_t eaddr,
					    u64 eval, unsigned long esize)
{
	struct kvm *kvm = its->dev->kvm;

	if (KVM_BUG_ON(esize != sizeof(eval), kvm))
		return -EINVAL;

	return kvm_write_guest_lock(kvm, eaddr, &eval, esize);
}

/*
 * This struct provides an intermediate representation of the fields contained
 * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC