Skip to content

Commit 9d0bee6

Browse files
committed
Merge branch kvm-arm64/vgic-its-fixes into kvmarm/next
* kvm-arm64/vgic-its-fixes: : Fixes for vgic-its save/restore, courtesy of Kunkun Jiang and Jing Zhang : : Address bugs where restoring an ITS consumes a stale DTE/ITE, which : may lead to either garbage mappings in the ITS or the overall restore : ioctl failing. The fix in both cases is to zero a DTE/ITE when its : translation has been invalidated by the guest. KVM: arm64: vgic-its: Clear ITE when DISCARD frees an ITE KVM: arm64: vgic-its: Clear DTE when MAPD unmaps a device KVM: arm64: vgic-its: Add a data length check in vgic_its_save_* Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
2 parents 6d4b81e + 7602ffd commit 9d0bee6

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

arch/arm64/kvm/vgic/vgic-its.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,9 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
782782

783783
ite = find_ite(its, device_id, event_id);
784784
if (ite && its_is_collection_mapped(ite->collection)) {
785+
struct its_device *device = find_its_device(its, device_id);
786+
int ite_esz = vgic_its_get_abi(its)->ite_esz;
787+
gpa_t gpa = device->itt_addr + ite->event_id * ite_esz;
785788
/*
786789
* Though the spec talks about removing the pending state, we
787790
* don't bother here since we clear the ITTE anyway and the
@@ -790,7 +793,8 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
790793
vgic_its_invalidate_cache(its);
791794

792795
its_free_ite(kvm, ite);
793-
return 0;
796+
797+
return vgic_its_write_entry_lock(its, gpa, 0, ite_esz);
794798
}
795799

796800
return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
@@ -1139,9 +1143,11 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
11391143
bool valid = its_cmd_get_validbit(its_cmd);
11401144
u8 num_eventid_bits = its_cmd_get_size(its_cmd);
11411145
gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
1146+
int dte_esz = vgic_its_get_abi(its)->dte_esz;
11421147
struct its_device *device;
1148+
gpa_t gpa;
11431149

1144-
if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
1150+
if (!vgic_its_check_id(its, its->baser_device_table, device_id, &gpa))
11451151
return E_ITS_MAPD_DEVICE_OOR;
11461152

11471153
if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
@@ -1162,7 +1168,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
11621168
* is an error, so we are done in any case.
11631169
*/
11641170
if (!valid)
1165-
return 0;
1171+
return vgic_its_write_entry_lock(its, gpa, 0, dte_esz);
11661172

11671173
device = vgic_its_alloc_device(its, device_id, itt_addr,
11681174
num_eventid_bits);
@@ -2086,7 +2092,6 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
20862092
static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
20872093
struct its_ite *ite, gpa_t gpa, int ite_esz)
20882094
{
2089-
struct kvm *kvm = its->dev->kvm;
20902095
u32 next_offset;
20912096
u64 val;
20922097

@@ -2095,7 +2100,8 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
20952100
((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
20962101
ite->collection->collection_id;
20972102
val = cpu_to_le64(val);
2098-
return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
2103+
2104+
return vgic_its_write_entry_lock(its, gpa, val, ite_esz);
20992105
}
21002106

21012107
/**
@@ -2239,7 +2245,6 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
22392245
static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
22402246
gpa_t ptr, int dte_esz)
22412247
{
2242-
struct kvm *kvm = its->dev->kvm;
22432248
u64 val, itt_addr_field;
22442249
u32 next_offset;
22452250

@@ -2250,7 +2255,8 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
22502255
(itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
22512256
(dev->num_eventid_bits - 1));
22522257
val = cpu_to_le64(val);
2253-
return vgic_write_guest_lock(kvm, ptr, &val, dte_esz);
2258+
2259+
return vgic_its_write_entry_lock(its, ptr, val, dte_esz);
22542260
}
22552261

22562262
/**
@@ -2437,7 +2443,8 @@ static int vgic_its_save_cte(struct vgic_its *its,
24372443
((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
24382444
collection->collection_id);
24392445
val = cpu_to_le64(val);
2440-
return vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz);
2446+
2447+
return vgic_its_write_entry_lock(its, gpa, val, esz);
24412448
}
24422449

24432450
/*
@@ -2453,8 +2460,7 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
24532460
u64 val;
24542461
int ret;
24552462

2456-
BUG_ON(esz > sizeof(val));
2457-
ret = kvm_read_guest_lock(kvm, gpa, &val, esz);
2463+
ret = vgic_its_read_entry_lock(its, gpa, &val, esz);
24582464
if (ret)
24592465
return ret;
24602466
val = le64_to_cpu(val);
@@ -2492,7 +2498,6 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
24922498
u64 baser = its->baser_coll_table;
24932499
gpa_t gpa = GITS_BASER_ADDR_48_to_52(baser);
24942500
struct its_collection *collection;
2495-
u64 val;
24962501
size_t max_size, filled = 0;
24972502
int ret, cte_esz = abi->cte_esz;
24982503

@@ -2516,10 +2521,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
25162521
* table is not fully filled, add a last dummy element
25172522
* with valid bit unset
25182523
*/
2519-
val = 0;
2520-
BUG_ON(cte_esz > sizeof(val));
2521-
ret = vgic_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
2522-
return ret;
2524+
return vgic_its_write_entry_lock(its, gpa, 0, cte_esz);
25232525
}
25242526

25252527
/*

arch/arm64/kvm/vgic/vgic.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,29 @@ static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,
146146
return ret;
147147
}
148148

149+
static inline int vgic_its_read_entry_lock(struct vgic_its *its, gpa_t eaddr,
150+
u64 *eval, unsigned long esize)
151+
{
152+
struct kvm *kvm = its->dev->kvm;
153+
154+
if (KVM_BUG_ON(esize != sizeof(*eval), kvm))
155+
return -EINVAL;
156+
157+
return kvm_read_guest_lock(kvm, eaddr, eval, esize);
158+
159+
}
160+
161+
static inline int vgic_its_write_entry_lock(struct vgic_its *its, gpa_t eaddr,
162+
u64 eval, unsigned long esize)
163+
{
164+
struct kvm *kvm = its->dev->kvm;
165+
166+
if (KVM_BUG_ON(esize != sizeof(eval), kvm))
167+
return -EINVAL;
168+
169+
return vgic_write_guest_lock(kvm, eaddr, &eval, esize);
170+
}
171+
149172
/*
150173
* This struct provides an intermediate representation of the fields contained
151174
* in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC

0 commit comments

Comments
 (0)