Skip to content

Commit f8f296e

Browse files
author
Claudio Imbrenda
committed
KVM: s390: vsie: Fix race in acquire_gmap_shadow()
The shadow gmap returned by gmap_create_shadow() could get dropped before taking the gmap->children_lock. This meant that the shadow gmap was sometimes being used while its reference count was 0. Fix this by taking the additional reference inside gmap_create_shadow() while still holding gmap->children_lock, instead of afterwards. Fixes: e38c884 ("KVM: s390: Switch to new gmap") Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
1 parent b6ab71a commit f8f296e

2 files changed

Lines changed: 17 additions & 4 deletions

File tree

arch/s390/kvm/gmap.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,8 @@ static int gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gma
11791179
* The shadow table will be removed automatically on any change to the
11801180
* PTE mapping for the source table.
11811181
*
1182+
* The returned shadow gmap will be returned with one extra reference.
1183+
*
11821184
* Return: A guest address space structure, ERR_PTR(-ENOMEM) if out of memory,
11831185
* ERR_PTR(-EAGAIN) if the caller has to retry and ERR_PTR(-EFAULT) if the
11841186
* parent gmap table could not be protected.
@@ -1189,10 +1191,13 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
11891191
struct gmap *sg, *new;
11901192
int rc;
11911193

1192-
scoped_guard(spinlock, &parent->children_lock)
1194+
scoped_guard(spinlock, &parent->children_lock) {
11931195
sg = gmap_find_shadow(parent, asce, edat_level);
1194-
if (sg)
1195-
return sg;
1196+
if (sg) {
1197+
gmap_get(sg);
1198+
return sg;
1199+
}
1200+
}
11961201
/* Create a new shadow gmap. */
11971202
new = gmap_new(parent->kvm, asce.r ? 1UL << (64 - PAGE_SHIFT) : asce_end(asce));
11981203
if (!new)
@@ -1206,6 +1211,7 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
12061211
sg = gmap_find_shadow(parent, asce, edat_level);
12071212
if (sg) {
12081213
gmap_put(new);
1214+
gmap_get(sg);
12091215
return sg;
12101216
}
12111217
if (asce.r) {
@@ -1219,16 +1225,19 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
12191225
}
12201226
gmap_add_child(parent, new);
12211227
/* Nothing to protect, return right away. */
1228+
gmap_get(new);
12221229
return new;
12231230
}
12241231
}
12251232

1233+
gmap_get(new);
12261234
new->parent = parent;
12271235
/* Protect while inserting, protects against invalidation races. */
12281236
rc = gmap_protect_asce_top_level(mc, new);
12291237
if (rc) {
12301238
new->parent = NULL;
12311239
gmap_put(new);
1240+
gmap_put(new);
12321241
return ERR_PTR(rc);
12331242
}
12341243
return new;

arch/s390/kvm/vsie.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,18 +1256,22 @@ static struct gmap *acquire_gmap_shadow(struct kvm_vcpu *vcpu, struct vsie_page
12561256
release_gmap_shadow(vsie_page);
12571257
}
12581258
}
1259+
again:
12591260
gmap = gmap_create_shadow(vcpu->arch.mc, vcpu->kvm->arch.gmap, asce, edat);
12601261
if (IS_ERR(gmap))
12611262
return gmap;
12621263
scoped_guard(spinlock, &vcpu->kvm->arch.gmap->children_lock) {
12631264
/* unlikely race condition, remove the previous shadow */
12641265
if (vsie_page->gmap_cache.gmap)
12651266
release_gmap_shadow(vsie_page);
1267+
if (!gmap->parent) {
1268+
gmap_put(gmap);
1269+
goto again;
1270+
}
12661271
vcpu->kvm->stat.gmap_shadow_create++;
12671272
list_add(&vsie_page->gmap_cache.list, &gmap->scb_users);
12681273
vsie_page->gmap_cache.gmap = gmap;
12691274
prefix_unmapped(vsie_page);
1270-
gmap_get(gmap);
12711275
}
12721276
return gmap;
12731277
}

0 commit comments

Comments
 (0)