Skip to content

Commit 19d6c5b

Browse files
author
Claudio Imbrenda
committed
KVM: s390: vsie: Fix unshadowing while shadowing
If shadowing causes the shadow gmap to get unshadowed, exit early to prevent an attempt to dereference the parent pointer, which at this point is NULL. Opportunistically add some more checks to prevent NULL parents. Fixes: a2c17f9 ("KVM: s390: New gmap code") Fixes: e5f98a6 ("KVM: s390: Add some helper functions needed for vSIE") Fixes: e38c884 ("KVM: s390: Switch to new gmap") Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
1 parent 0ec456b commit 19d6c5b

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

arch/s390/kvm/gaccess.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,8 @@ static int _do_shadow_pte(struct gmap *sg, gpa_t raddr, union pte *ptep_h, union
14491449
pgste_set_unlock(ptep_h, pgste);
14501450
if (rc)
14511451
return rc;
1452+
if (!sg->parent)
1453+
return -EAGAIN;
14521454

14531455
newpte = _pte(f->pfn, 0, !p, 0);
14541456
if (!pgste_get_trylock(ptep, &pgste))
@@ -1476,6 +1478,9 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
14761478
return rc;
14771479

14781480
do {
1481+
/* _gmap_crstep_xchg_atomic() could have unshadowed this shadow gmap */
1482+
if (!sg->parent)
1483+
return -EAGAIN;
14791484
oldcrste = READ_ONCE(*host);
14801485
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, f->writable, !p);
14811486
newcrste.s.fc1.d |= oldcrste.s.fc1.d;
@@ -1487,6 +1492,8 @@ static int _do_shadow_crste(struct gmap *sg, gpa_t raddr, union crste *host, uni
14871492
if (!newcrste.h.p && !f->writable)
14881493
return -EOPNOTSUPP;
14891494
} while (!_gmap_crstep_xchg_atomic(sg->parent, host, oldcrste, newcrste, f->gfn, false));
1495+
if (!sg->parent)
1496+
return -EAGAIN;
14901497

14911498
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p);
14921499
gfn = gpa_to_gfn(raddr);
@@ -1531,6 +1538,8 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
15311538
entries[i - 1].pfn, i, entries[i - 1].writable);
15321539
if (rc)
15331540
return rc;
1541+
if (!sg->parent)
1542+
return -EAGAIN;
15341543
}
15351544

15361545
rc = dat_entry_walk(NULL, entries[LEVEL_MEM].gfn, sg->parent->asce, DAT_WALK_LEAF,

arch/s390/kvm/gmap.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,14 +1160,20 @@ struct gmap_protect_asce_top_level {
11601160
static inline int __gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
11611161
struct gmap_protect_asce_top_level *context)
11621162
{
1163+
struct gmap *parent;
11631164
int rc, i;
11641165

11651166
guard(write_lock)(&sg->kvm->mmu_lock);
11661167

11671168
if (kvm_s390_array_needs_retry_safe(sg->kvm, context->seq, context->f))
11681169
return -EAGAIN;
11691170

1170-
scoped_guard(spinlock, &sg->parent->children_lock) {
1171+
parent = READ_ONCE(sg->parent);
1172+
if (!parent)
1173+
return -EAGAIN;
1174+
scoped_guard(spinlock, &parent->children_lock) {
1175+
if (READ_ONCE(sg->parent) != parent)
1176+
return -EAGAIN;
11711177
for (i = 0; i < CRST_TABLE_PAGES; i++) {
11721178
if (!context->f[i].valid)
11731179
continue;
@@ -1250,6 +1256,9 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
12501256
struct gmap *sg, *new;
12511257
int rc;
12521258

1259+
if (WARN_ON(!parent))
1260+
return ERR_PTR(-EINVAL);
1261+
12531262
scoped_guard(spinlock, &parent->children_lock) {
12541263
sg = gmap_find_shadow(parent, asce, edat_level);
12551264
if (sg) {

0 commit comments

Comments
 (0)