@@ -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+ */
9791006static 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+ */
24842534static 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
26232683static int vgic_its_commit_v0 (struct vgic_its * its )
0 commit comments