mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
If kvm_s390_set_cmma_bits() is asked to set CMMA values outside of a
memslot, PGM_ADDRESSING (5) is returned, instead of a negative error
value.
Same issue with kvm_s390_{g,s}et_skeys(), kvm_s390_keyop(), and
dat_reset_reference_bit().
Fix by returning -EFAULT whenever the return value would be > 0, which
is consistent with the behaviour before the gmap rewrite.
Fixes: e38c884df9 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-7-imbrenda@linux.ibm.com>
This commit is contained in:
parent
d301ade418
commit
d699986f11
|
|
@ -755,13 +755,15 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
|
|||
return rc;
|
||||
}
|
||||
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn)
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
|
||||
{
|
||||
union pgste pgste, old;
|
||||
union crste *crstep;
|
||||
union pte *ptep;
|
||||
int rc;
|
||||
|
||||
skey->skey = 0;
|
||||
|
||||
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -771,21 +773,23 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn)
|
|||
|
||||
if (!crste.h.fc || !crste.s.fc1.pr)
|
||||
return 0;
|
||||
return page_reset_referenced(large_crste_to_phys(*crstep, gfn));
|
||||
skey->skey = page_reset_referenced(large_crste_to_phys(*crstep, gfn)) << 1;
|
||||
return 0;
|
||||
}
|
||||
old = pgste_get_lock(ptep);
|
||||
pgste = old;
|
||||
|
||||
if (!ptep->h.i) {
|
||||
rc = page_reset_referenced(pte_origin(*ptep));
|
||||
pgste.hr = rc >> 1;
|
||||
skey->skey = page_reset_referenced(pte_origin(*ptep)) << 1;
|
||||
pgste.hr = skey->r;
|
||||
}
|
||||
rc |= (pgste.gr << 1) | pgste.gc;
|
||||
skey->r |= pgste.gr;
|
||||
skey->c |= pgste.gc;
|
||||
pgste.gr = 0;
|
||||
|
||||
dat_update_ptep_sd(old, pgste, ptep);
|
||||
pgste_set_unlock(ptep, pgste);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long dat_reset_skeys_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gf
|
|||
union skey skey, bool nq);
|
||||
int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gfn_t gfn,
|
||||
union skey skey, union skey *oldkey, bool nq, bool mr, bool mc);
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn);
|
||||
int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey);
|
||||
long dat_reset_skeys(union asce asce, gfn_t start);
|
||||
|
||||
unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ static int kvm_s390_keyop(struct kvm_s390_mmu_cache *mc, struct kvm *kvm, int op
|
|||
switch (op) {
|
||||
case KVM_S390_KEYOP_SSKE:
|
||||
r = dat_cond_set_storage_key(mc, asce, gfn, skey, &skey, 0, 0, 0);
|
||||
if (r >= 0)
|
||||
if (r == 0 || r == 1)
|
||||
return skey.skey;
|
||||
break;
|
||||
case KVM_S390_KEYOP_ISKE:
|
||||
|
|
@ -580,14 +580,14 @@ static int kvm_s390_keyop(struct kvm_s390_mmu_cache *mc, struct kvm *kvm, int op
|
|||
return skey.skey;
|
||||
break;
|
||||
case KVM_S390_KEYOP_RRBE:
|
||||
r = dat_reset_reference_bit(asce, gfn);
|
||||
if (r > 0)
|
||||
return r << 1;
|
||||
r = dat_reset_reference_bit(asce, gfn, &skey);
|
||||
if (!r)
|
||||
return skey.skey;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return r;
|
||||
return r > 0 ? -EFAULT : r;
|
||||
}
|
||||
|
||||
/* Section: device related */
|
||||
|
|
@ -2214,7 +2214,7 @@ static int kvm_s390_get_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
|||
}
|
||||
|
||||
kvfree(keys);
|
||||
return r;
|
||||
return r <= 0 ? r : -EFAULT;
|
||||
}
|
||||
|
||||
static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
||||
|
|
@ -2276,7 +2276,7 @@ static int kvm_s390_set_skeys(struct kvm *kvm, struct kvm_s390_skeys *args)
|
|||
kvm_s390_free_mmu_cache(mc);
|
||||
out:
|
||||
kvfree(keys);
|
||||
return r;
|
||||
return r <= 0 ? r : -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2386,7 +2386,7 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
|
|||
|
||||
set_bit(GMAP_FLAG_USES_CMM, &kvm->arch.gmap->flags);
|
||||
|
||||
return r;
|
||||
return r <= 0 ? r : -EFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ static int handle_iske(struct kvm_vcpu *vcpu)
|
|||
static int handle_rrbe(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long gaddr;
|
||||
union skey skey;
|
||||
int reg1, reg2;
|
||||
int rc;
|
||||
|
||||
|
|
@ -307,12 +308,12 @@ static int handle_rrbe(struct kvm_vcpu *vcpu)
|
|||
gaddr = kvm_s390_logical_to_effective(vcpu, gaddr);
|
||||
gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
|
||||
scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
|
||||
rc = dat_reset_reference_bit(vcpu->arch.gmap->asce, gpa_to_gfn(gaddr));
|
||||
rc = dat_reset_reference_bit(vcpu->arch.gmap->asce, gpa_to_gfn(gaddr), &skey);
|
||||
if (rc > 0)
|
||||
return kvm_s390_inject_program_int(vcpu, rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
kvm_s390_set_psw_cc(vcpu, rc);
|
||||
kvm_s390_set_psw_cc(vcpu, (skey.skey >> 1) & 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user