]> git.hungrycats.org Git - linux/commitdiff
KVM: arm64: vgic-its: Add a data length check in vgic_its_save_*
authorJing Zhang <jingzhangos@google.com>
Thu, 7 Nov 2024 21:41:34 +0000 (13:41 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Dec 2024 12:54:10 +0000 (13:54 +0100)
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: Kunkun Jiang <jiangkunkun@huawei.com>
[Jing: Update with the new entry read/write helpers]
Signed-off-by: Jing Zhang <jingzhangos@google.com>
Link: https://lore.kernel.org/r/20241107214137.428439-4-jingzhangos@google.com
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm64/kvm/vgic/vgic-its.c
arch/arm64/kvm/vgic/vgic.h

index c50cde439ac293fb68cfc773b04724a2ab57000c..9769911663a4b7a4d0f75a565e4d73b0724ac969 100644 (file)
@@ -2090,7 +2090,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;
 
@@ -2099,7 +2098,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 vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
+
+       return vgic_its_write_entry_lock(its, gpa, val, ite_esz);
 }
 
 /**
@@ -2243,7 +2243,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;
 
@@ -2254,7 +2253,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 vgic_write_guest_lock(kvm, ptr, &val, dte_esz);
+
+       return vgic_its_write_entry_lock(its, ptr, val, dte_esz);
 }
 
 /**
@@ -2441,7 +2441,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 vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz);
+
+       return vgic_its_write_entry_lock(its, gpa, val, esz);
 }
 
 /*
@@ -2457,8 +2458,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);
@@ -2496,7 +2496,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;
 
@@ -2520,10 +2519,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 = vgic_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
-       return ret;
+       return vgic_its_write_entry_lock(its, gpa, 0, cte_esz);
 }
 
 /*
index 8532bfe3fed40c6fcfb05515bf0709e59278d07b..82c1d24b243f5ecc1accbfa0f051762ad378740b 100644 (file)
@@ -146,6 +146,29 @@ static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,
        return ret;
 }
 
+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 vgic_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