mirror of
https://github.com/torvalds/linux.git
synced 2026-05-13 08:39:31 +02:00
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:a2c17f9270("KVM: s390: New gmap code") Fixes:e5f98a6899("KVM: s390: Add some helper functions needed for vSIE") Fixes:e38c884df9("KVM: s390: Switch to new gmap") Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
This commit is contained in:
parent
0ec456b8a5
commit
19d6c5b804
|
|
@ -1449,6 +1449,8 @@ static int _do_shadow_pte(struct gmap *sg, gpa_t raddr, union pte *ptep_h, union
|
|||
pgste_set_unlock(ptep_h, pgste);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (!sg->parent)
|
||||
return -EAGAIN;
|
||||
|
||||
newpte = _pte(f->pfn, 0, !p, 0);
|
||||
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
|
|||
return rc;
|
||||
|
||||
do {
|
||||
/* _gmap_crstep_xchg_atomic() could have unshadowed this shadow gmap */
|
||||
if (!sg->parent)
|
||||
return -EAGAIN;
|
||||
oldcrste = READ_ONCE(*host);
|
||||
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, f->writable, !p);
|
||||
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
|
|||
if (!newcrste.h.p && !f->writable)
|
||||
return -EOPNOTSUPP;
|
||||
} while (!_gmap_crstep_xchg_atomic(sg->parent, host, oldcrste, newcrste, f->gfn, false));
|
||||
if (!sg->parent)
|
||||
return -EAGAIN;
|
||||
|
||||
newcrste = _crste_fc1(f->pfn, oldcrste.h.tt, 0, !p);
|
||||
gfn = gpa_to_gfn(raddr);
|
||||
|
|
@ -1531,6 +1538,8 @@ static int _gaccess_do_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
|
|||
entries[i - 1].pfn, i, entries[i - 1].writable);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (!sg->parent)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
rc = dat_entry_walk(NULL, entries[LEVEL_MEM].gfn, sg->parent->asce, DAT_WALK_LEAF,
|
||||
|
|
|
|||
|
|
@ -1160,6 +1160,7 @@ struct gmap_protect_asce_top_level {
|
|||
static inline int __gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, struct gmap *sg,
|
||||
struct gmap_protect_asce_top_level *context)
|
||||
{
|
||||
struct gmap *parent;
|
||||
int rc, i;
|
||||
|
||||
guard(write_lock)(&sg->kvm->mmu_lock);
|
||||
|
|
@ -1167,7 +1168,12 @@ static inline int __gmap_protect_asce_top_level(struct kvm_s390_mmu_cache *mc, s
|
|||
if (kvm_s390_array_needs_retry_safe(sg->kvm, context->seq, context->f))
|
||||
return -EAGAIN;
|
||||
|
||||
scoped_guard(spinlock, &sg->parent->children_lock) {
|
||||
parent = READ_ONCE(sg->parent);
|
||||
if (!parent)
|
||||
return -EAGAIN;
|
||||
scoped_guard(spinlock, &parent->children_lock) {
|
||||
if (READ_ONCE(sg->parent) != parent)
|
||||
return -EAGAIN;
|
||||
for (i = 0; i < CRST_TABLE_PAGES; i++) {
|
||||
if (!context->f[i].valid)
|
||||
continue;
|
||||
|
|
@ -1250,6 +1256,9 @@ struct gmap *gmap_create_shadow(struct kvm_s390_mmu_cache *mc, struct gmap *pare
|
|||
struct gmap *sg, *new;
|
||||
int rc;
|
||||
|
||||
if (WARN_ON(!parent))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
scoped_guard(spinlock, &parent->children_lock) {
|
||||
sg = gmap_find_shadow(parent, asce, edat_level);
|
||||
if (sg) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user