diff options
author | Eric Auger <eric.auger@redhat.com> | 2017-10-26 11:23:06 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2017-10-28 22:25:06 -0400 |
commit | c2385eaa6c5a87cdc4e04ed589ae103ca3297c84 (patch) | |
tree | 712404cee49dc091b21b2923b531697197a940c8 | |
parent | c9b51bb60d944067f36f67750e19c18c3cc2697c (diff) |
KVM: arm/arm64: vgic-its: Check GITS_BASER Valid bit before saving tables
At the moment we don't properly check the GITS_BASER<n>.Valid
bit before saving the collection and device tables.
On vgic_its_save_collection_table() we use the GITS_BASER gpa
field whereas the Valid bit should be used.
On vgic_its_save_device_tables() there is no check. This can
cause various bugs, among which a subsequent fault when accessing
the table in guest memory.
Let's systematically check the Valid bit before doing anything.
We also uniformize the code between save and restore.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r-- | virt/kvm/arm/vgic/vgic-its.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index e69ef7d27fde..547f12dc4d54 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c | |||
@@ -2067,11 +2067,12 @@ static int vgic_its_device_cmp(void *priv, struct list_head *a, | |||
2067 | static int vgic_its_save_device_tables(struct vgic_its *its) | 2067 | static int vgic_its_save_device_tables(struct vgic_its *its) |
2068 | { | 2068 | { |
2069 | const struct vgic_its_abi *abi = vgic_its_get_abi(its); | 2069 | const struct vgic_its_abi *abi = vgic_its_get_abi(its); |
2070 | u64 baser = its->baser_device_table; | ||
2070 | struct its_device *dev; | 2071 | struct its_device *dev; |
2071 | int dte_esz = abi->dte_esz; | 2072 | int dte_esz = abi->dte_esz; |
2072 | u64 baser; | ||
2073 | 2073 | ||
2074 | baser = its->baser_device_table; | 2074 | if (!(baser & GITS_BASER_VALID)) |
2075 | return 0; | ||
2075 | 2076 | ||
2076 | list_sort(NULL, &its->device_list, vgic_its_device_cmp); | 2077 | list_sort(NULL, &its->device_list, vgic_its_device_cmp); |
2077 | 2078 | ||
@@ -2215,17 +2216,17 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz) | |||
2215 | static int vgic_its_save_collection_table(struct vgic_its *its) | 2216 | static int vgic_its_save_collection_table(struct vgic_its *its) |
2216 | { | 2217 | { |
2217 | const struct vgic_its_abi *abi = vgic_its_get_abi(its); | 2218 | const struct vgic_its_abi *abi = vgic_its_get_abi(its); |
2219 | u64 baser = its->baser_coll_table; | ||
2220 | gpa_t gpa = BASER_ADDRESS(baser); | ||
2218 | struct its_collection *collection; | 2221 | struct its_collection *collection; |
2219 | u64 val; | 2222 | u64 val; |
2220 | gpa_t gpa; | ||
2221 | size_t max_size, filled = 0; | 2223 | size_t max_size, filled = 0; |
2222 | int ret, cte_esz = abi->cte_esz; | 2224 | int ret, cte_esz = abi->cte_esz; |
2223 | 2225 | ||
2224 | gpa = BASER_ADDRESS(its->baser_coll_table); | 2226 | if (!(baser & GITS_BASER_VALID)) |
2225 | if (!gpa) | ||
2226 | return 0; | 2227 | return 0; |
2227 | 2228 | ||
2228 | max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K; | 2229 | max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; |
2229 | 2230 | ||
2230 | list_for_each_entry(collection, &its->collection_list, coll_list) { | 2231 | list_for_each_entry(collection, &its->collection_list, coll_list) { |
2231 | ret = vgic_its_save_cte(its, collection, gpa, cte_esz); | 2232 | ret = vgic_its_save_cte(its, collection, gpa, cte_esz); |
@@ -2256,17 +2257,18 @@ static int vgic_its_save_collection_table(struct vgic_its *its) | |||
2256 | static int vgic_its_restore_collection_table(struct vgic_its *its) | 2257 | static int vgic_its_restore_collection_table(struct vgic_its *its) |
2257 | { | 2258 | { |
2258 | const struct vgic_its_abi *abi = vgic_its_get_abi(its); | 2259 | const struct vgic_its_abi *abi = vgic_its_get_abi(its); |
2260 | u64 baser = its->baser_coll_table; | ||
2259 | int cte_esz = abi->cte_esz; | 2261 | int cte_esz = abi->cte_esz; |
2260 | size_t max_size, read = 0; | 2262 | size_t max_size, read = 0; |
2261 | gpa_t gpa; | 2263 | gpa_t gpa; |
2262 | int ret; | 2264 | int ret; |
2263 | 2265 | ||
2264 | if (!(its->baser_coll_table & GITS_BASER_VALID)) | 2266 | if (!(baser & GITS_BASER_VALID)) |
2265 | return 0; | 2267 | return 0; |
2266 | 2268 | ||
2267 | gpa = BASER_ADDRESS(its->baser_coll_table); | 2269 | gpa = BASER_ADDRESS(baser); |
2268 | 2270 | ||
2269 | max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K; | 2271 | max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; |
2270 | 2272 | ||
2271 | while (read < max_size) { | 2273 | while (read < max_size) { |
2272 | ret = vgic_its_restore_cte(its, gpa, cte_esz); | 2274 | ret = vgic_its_restore_cte(its, gpa, cte_esz); |