Skip to content

Commit 5c0ad55

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/its-save-restore-fixes-5.19 into kvmarm-master/next
* kvm-arm64/its-save-restore-fixes-5.19: : . : Tighten the ITS save/restore infrastructure to fail early rather : than late. Patches courtesy of Rocardo Koller. : . KVM: arm64: vgic: Undo work in failed ITS restores KVM: arm64: vgic: Do not ignore vgic_its_restore_cte failures KVM: arm64: vgic: Add more checks when restoring ITS tables KVM: arm64: vgic: Check that new ITEs could be saved in guest memory Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents 822ca7f + 8c5e74c commit 5c0ad55

1 file changed

Lines changed: 78 additions & 18 deletions

File tree

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

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,18 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
894894
return update_affinity(ite->irq, vcpu);
895895
}
896896

897+
static bool __is_visible_gfn_locked(struct vgic_its *its, gpa_t gpa)
898+
{
899+
gfn_t gfn = gpa >> PAGE_SHIFT;
900+
int idx;
901+
bool ret;
902+
903+
idx = srcu_read_lock(&its->dev->kvm->srcu);
904+
ret = kvm_is_visible_gfn(its->dev->kvm, gfn);
905+
srcu_read_unlock(&its->dev->kvm->srcu, idx);
906+
return ret;
907+
}
908+
897909
/*
898910
* Check whether an ID can be stored into the corresponding guest table.
899911
* For a direct table this is pretty easy, but gets a bit nasty for
@@ -908,9 +920,7 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
908920
u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
909921
phys_addr_t base = GITS_BASER_ADDR_48_to_52(baser);
910922
int esz = GITS_BASER_ENTRY_SIZE(baser);
911-
int index, idx;
912-
gfn_t gfn;
913-
bool ret;
923+
int index;
914924

915925
switch (type) {
916926
case GITS_BASER_TYPE_DEVICE:
@@ -933,12 +943,11 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
933943
return false;
934944

935945
addr = base + id * esz;
936-
gfn = addr >> PAGE_SHIFT;
937946

938947
if (eaddr)
939948
*eaddr = addr;
940949

941-
goto out;
950+
return __is_visible_gfn_locked(its, addr);
942951
}
943952

944953
/* calculate and check the index into the 1st level */
@@ -964,27 +973,42 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
964973
/* Find the address of the actual entry */
965974
index = id % (SZ_64K / esz);
966975
indirect_ptr += index * esz;
967-
gfn = indirect_ptr >> PAGE_SHIFT;
968976

969977
if (eaddr)
970978
*eaddr = indirect_ptr;
971979

972-
out:
973-
idx = srcu_read_lock(&its->dev->kvm->srcu);
974-
ret = kvm_is_visible_gfn(its->dev->kvm, gfn);
975-
srcu_read_unlock(&its->dev->kvm->srcu, idx);
976-
return ret;
980+
return __is_visible_gfn_locked(its, indirect_ptr);
981+
}
982+
983+
/*
984+
* Check whether an event ID can be stored in the corresponding Interrupt
985+
* Translation Table, which starts at device->itt_addr.
986+
*/
987+
static bool vgic_its_check_event_id(struct vgic_its *its, struct its_device *device,
988+
u32 event_id)
989+
{
990+
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
991+
int ite_esz = abi->ite_esz;
992+
gpa_t gpa;
993+
994+
/* max table size is: BIT_ULL(device->num_eventid_bits) * ite_esz */
995+
if (event_id >= BIT_ULL(device->num_eventid_bits))
996+
return false;
997+
998+
gpa = device->itt_addr + event_id * ite_esz;
999+
return __is_visible_gfn_locked(its, gpa);
9771000
}
9781001

1002+
/*
1003+
* Add a new collection into the ITS collection table.
1004+
* Returns 0 on success, and a negative error value for generic errors.
1005+
*/
9791006
static int vgic_its_alloc_collection(struct vgic_its *its,
9801007
struct its_collection **colp,
9811008
u32 coll_id)
9821009
{
9831010
struct its_collection *collection;
9841011

985-
if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
986-
return E_ITS_MAPC_COLLECTION_OOR;
987-
9881012
collection = kzalloc(sizeof(*collection), GFP_KERNEL_ACCOUNT);
9891013
if (!collection)
9901014
return -ENOMEM;
@@ -1061,7 +1085,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
10611085
if (!device)
10621086
return E_ITS_MAPTI_UNMAPPED_DEVICE;
10631087

1064-
if (event_id >= BIT_ULL(device->num_eventid_bits))
1088+
if (!vgic_its_check_event_id(its, device, event_id))
10651089
return E_ITS_MAPTI_ID_OOR;
10661090

10671091
if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
@@ -1078,7 +1102,12 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
10781102

10791103
collection = find_collection(its, coll_id);
10801104
if (!collection) {
1081-
int ret = vgic_its_alloc_collection(its, &collection, coll_id);
1105+
int ret;
1106+
1107+
if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
1108+
return E_ITS_MAPC_COLLECTION_OOR;
1109+
1110+
ret = vgic_its_alloc_collection(its, &collection, coll_id);
10821111
if (ret)
10831112
return ret;
10841113
new_coll = collection;
@@ -1233,6 +1262,10 @@ static int vgic_its_cmd_handle_mapc(struct kvm *kvm, struct vgic_its *its,
12331262
if (!collection) {
12341263
int ret;
12351264

1265+
if (!vgic_its_check_id(its, its->baser_coll_table,
1266+
coll_id, NULL))
1267+
return E_ITS_MAPC_COLLECTION_OOR;
1268+
12361269
ret = vgic_its_alloc_collection(its, &collection,
12371270
coll_id);
12381271
if (ret)
@@ -2195,6 +2228,9 @@ static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
21952228
if (!collection)
21962229
return -EINVAL;
21972230

2231+
if (!vgic_its_check_event_id(its, dev, event_id))
2232+
return -EINVAL;
2233+
21982234
ite = vgic_its_alloc_ite(dev, collection, event_id);
21992235
if (IS_ERR(ite))
22002236
return PTR_ERR(ite);
@@ -2203,8 +2239,10 @@ static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
22032239
vcpu = kvm_get_vcpu(kvm, collection->target_addr);
22042240

22052241
irq = vgic_add_lpi(kvm, lpi_id, vcpu);
2206-
if (IS_ERR(irq))
2242+
if (IS_ERR(irq)) {
2243+
its_free_ite(kvm, ite);
22072244
return PTR_ERR(irq);
2245+
}
22082246
ite->irq = irq;
22092247

22102248
return offset;
@@ -2316,6 +2354,7 @@ static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
23162354
void *ptr, void *opaque)
23172355
{
23182356
struct its_device *dev;
2357+
u64 baser = its->baser_device_table;
23192358
gpa_t itt_addr;
23202359
u8 num_eventid_bits;
23212360
u64 entry = *(u64 *)ptr;
@@ -2336,6 +2375,9 @@ static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
23362375
/* dte entry is valid */
23372376
offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
23382377

2378+
if (!vgic_its_check_id(its, baser, id, NULL))
2379+
return -EINVAL;
2380+
23392381
dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
23402382
if (IS_ERR(dev))
23412383
return PTR_ERR(dev);
@@ -2465,6 +2507,9 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
24652507
if (ret > 0)
24662508
ret = 0;
24672509

2510+
if (ret < 0)
2511+
vgic_its_free_device_list(its->dev->kvm, its);
2512+
24682513
return ret;
24692514
}
24702515

@@ -2481,6 +2526,11 @@ static int vgic_its_save_cte(struct vgic_its *its,
24812526
return kvm_write_guest_lock(its->dev->kvm, gpa, &val, esz);
24822527
}
24832528

2529+
/*
2530+
* Restore a collection entry into the ITS collection table.
2531+
* Return +1 on success, 0 if the entry was invalid (which should be
2532+
* interpreted as end-of-table), and a negative error value for generic errors.
2533+
*/
24842534
static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
24852535
{
24862536
struct its_collection *collection;
@@ -2507,6 +2557,10 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
25072557
collection = find_collection(its, coll_id);
25082558
if (collection)
25092559
return -EEXIST;
2560+
2561+
if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
2562+
return -EINVAL;
2563+
25102564
ret = vgic_its_alloc_collection(its, &collection, coll_id);
25112565
if (ret)
25122566
return ret;
@@ -2586,6 +2640,9 @@ static int vgic_its_restore_collection_table(struct vgic_its *its)
25862640
if (ret > 0)
25872641
return 0;
25882642

2643+
if (ret < 0)
2644+
vgic_its_free_collection_list(its->dev->kvm, its);
2645+
25892646
return ret;
25902647
}
25912648

@@ -2617,7 +2674,10 @@ static int vgic_its_restore_tables_v0(struct vgic_its *its)
26172674
if (ret)
26182675
return ret;
26192676

2620-
return vgic_its_restore_device_tables(its);
2677+
ret = vgic_its_restore_device_tables(its);
2678+
if (ret)
2679+
vgic_its_free_collection_list(its->dev->kvm, its);
2680+
return ret;
26212681
}
26222682

26232683
static int vgic_its_commit_v0(struct vgic_its *its)

0 commit comments

Comments
 (0)