Skip to content

Commit 3b2c81d

Browse files
Marc Zyngieroupton
authored andcommitted
KVM: arm64: vgic-its: Add stronger type-checking to the ITS entry sizes
The ITS ABI infrastructure allows for some pretty lax code, where the size of the data doesn't have to match the size of the entry, potentially leading to a collection of interesting bugs. Commit 7fe28d7 ("KVM: arm64: vgic-its: Add a data length check in vgic_its_save_*") added some checks, but starts by implicitly casting all writes to a 64bit value, hiding some of the issues. Instead, introduce macros that will check the data type actually used for dealing with the table entries. The macros are taking a symbolic entry type that is used to fetch the size of the entry type for the current ABI. This immediately catches a couple of low-impact gotchas (zero values that are implicitly 32bit), easy enough to fix. Given that we currently only have a single ABI, hardcode a couple of BUILD_BUG_ON()s that will fire if we use anything but a 64bit quantity, and some (currently unreachable) fallback code that may become useful one day. Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20241117165757.247686-5-maz@kernel.org Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent e7619f2 commit 3b2c81d

File tree

2 files changed

+50
-42
lines changed

2 files changed

+50
-42
lines changed

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

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,41 @@ static int vgic_its_commit_v0(struct vgic_its *its);
3131
static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
3232
struct kvm_vcpu *filter_vcpu, bool needs_inv);
3333

34+
#define vgic_its_read_entry_lock(i, g, valp, t) \
35+
({ \
36+
int __sz = vgic_its_get_abi(i)->t##_esz; \
37+
struct kvm *__k = (i)->dev->kvm; \
38+
int __ret; \
39+
\
40+
BUILD_BUG_ON(NR_ITS_ABIS == 1 && \
41+
sizeof(*(valp)) != ABI_0_ESZ); \
42+
if (NR_ITS_ABIS > 1 && \
43+
KVM_BUG_ON(__sz != sizeof(*(valp)), __k)) \
44+
__ret = -EINVAL; \
45+
else \
46+
__ret = kvm_read_guest_lock(__k, (g), \
47+
valp, __sz); \
48+
__ret; \
49+
})
50+
51+
#define vgic_its_write_entry_lock(i, g, val, t) \
52+
({ \
53+
int __sz = vgic_its_get_abi(i)->t##_esz; \
54+
struct kvm *__k = (i)->dev->kvm; \
55+
typeof(val) __v = (val); \
56+
int __ret; \
57+
\
58+
BUILD_BUG_ON(NR_ITS_ABIS == 1 && \
59+
sizeof(__v) != ABI_0_ESZ); \
60+
if (NR_ITS_ABIS > 1 && \
61+
KVM_BUG_ON(__sz != sizeof(__v), __k)) \
62+
__ret = -EINVAL; \
63+
else \
64+
__ret = vgic_write_guest_lock(__k, (g), \
65+
&__v, __sz); \
66+
__ret; \
67+
})
68+
3469
/*
3570
* Creates a new (reference to a) struct vgic_irq for a given LPI.
3671
* If this LPI is already mapped on another ITS, we increase its refcount
@@ -794,7 +829,7 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
794829

795830
its_free_ite(kvm, ite);
796831

797-
return vgic_its_write_entry_lock(its, gpa, 0, ite_esz);
832+
return vgic_its_write_entry_lock(its, gpa, 0ULL, ite);
798833
}
799834

800835
return E_ITS_DISCARD_UNMAPPED_INTERRUPT;
@@ -1143,7 +1178,6 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
11431178
bool valid = its_cmd_get_validbit(its_cmd);
11441179
u8 num_eventid_bits = its_cmd_get_size(its_cmd);
11451180
gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
1146-
int dte_esz = vgic_its_get_abi(its)->dte_esz;
11471181
struct its_device *device;
11481182
gpa_t gpa;
11491183

@@ -1168,7 +1202,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
11681202
* is an error, so we are done in any case.
11691203
*/
11701204
if (!valid)
1171-
return vgic_its_write_entry_lock(its, gpa, 0, dte_esz);
1205+
return vgic_its_write_entry_lock(its, gpa, 0ULL, dte);
11721206

11731207
device = vgic_its_alloc_device(its, device_id, itt_addr,
11741208
num_eventid_bits);
@@ -2090,7 +2124,7 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
20902124
* vgic_its_save_ite - Save an interrupt translation entry at @gpa
20912125
*/
20922126
static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
2093-
struct its_ite *ite, gpa_t gpa, int ite_esz)
2127+
struct its_ite *ite, gpa_t gpa)
20942128
{
20952129
u32 next_offset;
20962130
u64 val;
@@ -2101,7 +2135,7 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
21012135
ite->collection->collection_id;
21022136
val = cpu_to_le64(val);
21032137

2104-
return vgic_its_write_entry_lock(its, gpa, val, ite_esz);
2138+
return vgic_its_write_entry_lock(its, gpa, val, ite);
21052139
}
21062140

21072141
/**
@@ -2201,7 +2235,7 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
22012235
if (ite->irq->hw && !kvm_vgic_global_state.has_gicv4_1)
22022236
return -EACCES;
22032237

2204-
ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);
2238+
ret = vgic_its_save_ite(its, device, ite, gpa);
22052239
if (ret)
22062240
return ret;
22072241
}
@@ -2240,10 +2274,9 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
22402274
* @its: ITS handle
22412275
* @dev: ITS device
22422276
* @ptr: GPA
2243-
* @dte_esz: device table entry size
22442277
*/
22452278
static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
2246-
gpa_t ptr, int dte_esz)
2279+
gpa_t ptr)
22472280
{
22482281
u64 val, itt_addr_field;
22492282
u32 next_offset;
@@ -2256,7 +2289,7 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
22562289
(dev->num_eventid_bits - 1));
22572290
val = cpu_to_le64(val);
22582291

2259-
return vgic_its_write_entry_lock(its, ptr, val, dte_esz);
2292+
return vgic_its_write_entry_lock(its, ptr, val, dte);
22602293
}
22612294

22622295
/**
@@ -2332,10 +2365,8 @@ static int vgic_its_device_cmp(void *priv, const struct list_head *a,
23322365
*/
23332366
static int vgic_its_save_device_tables(struct vgic_its *its)
23342367
{
2335-
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
23362368
u64 baser = its->baser_device_table;
23372369
struct its_device *dev;
2338-
int dte_esz = abi->dte_esz;
23392370

23402371
if (!(baser & GITS_BASER_VALID))
23412372
return 0;
@@ -2354,7 +2385,7 @@ static int vgic_its_save_device_tables(struct vgic_its *its)
23542385
if (ret)
23552386
return ret;
23562387

2357-
ret = vgic_its_save_dte(its, dev, eaddr, dte_esz);
2388+
ret = vgic_its_save_dte(its, dev, eaddr);
23582389
if (ret)
23592390
return ret;
23602391
}
@@ -2435,7 +2466,7 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
24352466

24362467
static int vgic_its_save_cte(struct vgic_its *its,
24372468
struct its_collection *collection,
2438-
gpa_t gpa, int esz)
2469+
gpa_t gpa)
24392470
{
24402471
u64 val;
24412472

@@ -2444,23 +2475,23 @@ static int vgic_its_save_cte(struct vgic_its *its,
24442475
collection->collection_id);
24452476
val = cpu_to_le64(val);
24462477

2447-
return vgic_its_write_entry_lock(its, gpa, val, esz);
2478+
return vgic_its_write_entry_lock(its, gpa, val, cte);
24482479
}
24492480

24502481
/*
24512482
* Restore a collection entry into the ITS collection table.
24522483
* Return +1 on success, 0 if the entry was invalid (which should be
24532484
* interpreted as end-of-table), and a negative error value for generic errors.
24542485
*/
2455-
static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
2486+
static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa)
24562487
{
24572488
struct its_collection *collection;
24582489
struct kvm *kvm = its->dev->kvm;
24592490
u32 target_addr, coll_id;
24602491
u64 val;
24612492
int ret;
24622493

2463-
ret = vgic_its_read_entry_lock(its, gpa, &val, esz);
2494+
ret = vgic_its_read_entry_lock(its, gpa, &val, cte);
24642495
if (ret)
24652496
return ret;
24662497
val = le64_to_cpu(val);
@@ -2507,7 +2538,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
25072538
max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
25082539

25092540
list_for_each_entry(collection, &its->collection_list, coll_list) {
2510-
ret = vgic_its_save_cte(its, collection, gpa, cte_esz);
2541+
ret = vgic_its_save_cte(its, collection, gpa);
25112542
if (ret)
25122543
return ret;
25132544
gpa += cte_esz;
@@ -2521,7 +2552,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
25212552
* table is not fully filled, add a last dummy element
25222553
* with valid bit unset
25232554
*/
2524-
return vgic_its_write_entry_lock(its, gpa, 0, cte_esz);
2555+
return vgic_its_write_entry_lock(its, gpa, 0ULL, cte);
25252556
}
25262557

25272558
/*
@@ -2546,7 +2577,7 @@ static int vgic_its_restore_collection_table(struct vgic_its *its)
25462577
max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
25472578

25482579
while (read < max_size) {
2549-
ret = vgic_its_restore_cte(its, gpa, cte_esz);
2580+
ret = vgic_its_restore_cte(its, gpa);
25502581
if (ret <= 0)
25512582
break;
25522583
gpa += cte_esz;

arch/arm64/kvm/vgic/vgic.h

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -146,29 +146,6 @@ 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-
172149
/*
173150
* This struct provides an intermediate representation of the fields contained
174151
* in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC

0 commit comments

Comments
 (0)