* [PATCH v6 00/14] KVM: s390: Misc fixes
@ 2026-07-30 16:27 Claudio Imbrenda
2026-07-30 16:27 ` [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
` (13 more replies)
0 siblings, 14 replies; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
Fix a bunch of small issues that came up during the previous round of fixes.
They are mostly extremely unlikely races, but they should be fixed
nonetheless.
v5->v6
* Move the memory accesses in sca_ext_call_pending() and
sca_inject_ext_call() so that they only happen after the newly
introduced checks. Otherwise an out of bounds access was still possible.
* Completely fence the KVM_S390_INTERRUPT ioctl for UCONTROL VMs.
* Move page table updates from kvm_arch_commit_memory_region() to
kvm_arch_prepare_memory_region(), so that failures are not ignored.
v4->v5
* Improve / fix some comments
* Undo handle_mvpg_pei() changes
* cmma_d_count_pte() now clears the cmma_d bit, to avoid double counting
* Improve some patch descriptions
* Trigger KVM_BUG_ON() in sca_ext_call_pending() and
sca_inject_ext_call() if called on UCONTROL vCPUs
* Reshuffle the order of the patches to hopefully get fewer false
positives from sashiko
* Check and free cbrlo only if it's not zero
v3->v4
* Improve patch descriptions, add comments
* Use smp_store_release and smp_load_acquire in the first patch
* Multiple fixes in patch 4: potential NULL pointer dereference,
incorrect behaviour in low memory condition
* Rework patch 8 to use scope-based cleanup instead of gotos.
* Three new patches:
- KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory
- KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
- KVM: s390: Fix sca_clear_ext_call() for UCONTROL
v2->v3
* Use READ_ONCE to pair with WRITE_ONCE in the first patch
* Fix leaking PGM_ADDRESSING also in kvm_s390_keyop() and related functions
* Fix and improve commit messages
* Use slots_arch_lock instead of slots_lock for ESSA operations
* Use normal spin_{,un}lock() functions instead of scoped_guard to avoid
mixing the two styles
* Use the newly introduced vcpu->arch.initialized to determine whether the
SCA entry needs to be cleared
* Improve handling of -EINTR; handle_mvpg_pei() needed some refactoring to
deal with it properly
* Three new patches:
- Free the mmu cache when kvm_arch_vcpu_create() fails
- Fix ordering when adding to SCA
- Fix cleanup in kvm_s390_pv_create_cpu()
v1->v2
* Drop some patches that have been picked upstream in the meantime.
* Drop patch 3, as it was trying to fix a bug that does not exist
* Avoid the NULL gmap dereference by using a flag
* Fix the return value of kvm_s390_[gp]et_skeys too
* Use kvm->slots_arch_lock instead of kvm->slots_lock for CMMA and ESSA
handling, to avoid potential deadlocks with the RCU.
* Three new patches to fix other issues that came out while fixing the
other issues
Claudio Imbrenda (14):
KVM: s390: Fix unlikely NULL gmap dereference
KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
KVM: s390: Fix overclearing ESCA in case of error
KVM: s390: ucontrol: Fix sca_clear_ext_call()
KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
KVM: s390: Fix race in __do_essa()
KVM: s390: cmma: Fix dirty tracking when removing memslot
KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
KVM: s390: Return -EINTR if a signal is pending while faulting-in
KVM: s390: Fix ordering when adding to SCA
KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory
KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region()
arch/s390/include/asm/kvm_host.h | 1 +
arch/s390/kvm/dat.c | 23 ++--
arch/s390/kvm/dat.h | 2 +-
arch/s390/kvm/faultin.c | 6 +-
arch/s390/kvm/interrupt.c | 19 +++-
arch/s390/kvm/kvm-s390.c | 187 ++++++++++++++++++-------------
arch/s390/kvm/priv.c | 10 +-
arch/s390/kvm/pv.c | 43 +++----
8 files changed, 172 insertions(+), 119 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:50 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
` (12 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
When creating a new vCPU, kvm_vm_ioctl_create_vcpu() will call
kvm_arch_vcpu_postcreate() after the file descriptor for the new vCPU
has been created. The new file descriptor has not been returned yet,
but a malicious userspace program could try to guess it.
If a malicious userspace program manages to start the newly created vCPU
before kvm_arch_vcpu_postcreate() is called, __vcpu_run() will try to
dereference vcpu->arch.gmap and trigger a NULL pointer dereference.
Fix this by adding a new field to struct kvm_vcpu_arch to keep track of
the initialization status of the vCPU. Refuse to run a vCPU that is not
fully initialized.
Fixes: dafd032a15f8 ("KVM: s390: move vcpu specific initalization to a later point")
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
arch/s390/include/asm/kvm_host.h | 1 +
arch/s390/kvm/kvm-s390.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index eaa34c5bd3c1..edf75b6ad20c 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -440,6 +440,7 @@ struct kvm_vcpu_arch {
bool skey_enabled;
/* Indicator if the access registers have been loaded from guest */
bool acrs_loaded;
+ bool initialized;
struct kvm_s390_pv_vcpu pv;
union diag318_info diag318_info;
struct kvm_s390_mmu_cache *mc;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 150b5dd2170e..f86b4b0b356f 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3613,6 +3613,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0 ||
vcpu->kvm->arch.user_operexec)
vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
+
+ /* Pairs with smp_load_acquire() in kvm_arch_vcpu_ioctl_run() and kvm_arch_vcpu_ioctl() */
+ smp_store_release(&vcpu->arch.initialized, true);
}
static bool kvm_has_pckmo_subfunc(struct kvm *kvm, unsigned long nr)
@@ -5039,6 +5042,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
kvm_run->kvm_dirty_regs & ~KVM_SYNC_S390_VALID_FIELDS)
return -EINVAL;
+ /* Pairs with smp_store_release() in kvm_arch_vcpu_postcreate() */
+ if (!smp_load_acquire(&vcpu->arch.initialized))
+ return -EINVAL;
+
vcpu_load(vcpu);
if (guestdbg_exit_pending(vcpu)) {
@@ -5523,6 +5530,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
long r;
u16 rc, rrc;
+ /* Pairs with smp_store_release() in kvm_arch_vcpu_postcreate() */
+ if (!smp_load_acquire(&vcpu->arch.initialized))
+ return -EINVAL;
+
vcpu_load(vcpu);
switch (ioctl) {
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
2026-07-30 16:27 ` [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:55 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
` (11 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
In some cases kvm_s390_vcpu_unsetup_cmma() can be called with a 0
cbrlo; in such cases, if running with V != R, free_page() will attempt
to free physical page 0.
Fix by freeing cbrlo only if it's non-zero.
Fixes: b31605c12f4e ("KVM: s390: make cmma usage conditionally")
Fixes: 29b40f105ec8 ("KVM: s390: protvirt: Add initial vm and cpu lifecycle handling")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
arch/s390/kvm/kvm-s390.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index f86b4b0b356f..9ec5833a0973 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3677,7 +3677,8 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu)
{
- free_page((unsigned long)phys_to_virt(vcpu->arch.sie_block->cbrlo));
+ if (vcpu->arch.sie_block->cbrlo)
+ free_page((unsigned long)phys_to_virt(vcpu->arch.sie_block->cbrlo));
vcpu->arch.sie_block->cbrlo = 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
2026-07-30 16:27 ` [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
2026-07-30 16:27 ` [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 17:04 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
` (10 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
If an attempt is made to create a vCPU with an already existing ID,
the duplicated vCPU will be destroyed. When destroying a vCPU, its
ESCA entry will be cleared. In the above scenario, the spurious
duplicate vCPU is destroyed, but the ESCA entry corresponding to the
original vCPU is cleared.
Fix by skipping clearing the ESCA entry if the vCPU creation was not
successful, i.e. if the pointer to the ESCA in the state description is
not set.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
---
arch/s390/kvm/interrupt.c | 2 +-
arch/s390/kvm/kvm-s390.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 9e3e6b0d72ad..2acdff130fa6 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -86,7 +86,7 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
struct esca_block *sca = vcpu->kvm->arch.sca;
union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
- if (!kvm_s390_use_sca_entries())
+ if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized)
return;
kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 9ec5833a0973..58cec3703c2d 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3461,7 +3461,7 @@ static void sca_del_vcpu(struct kvm_vcpu *vcpu)
{
struct esca_block *sca = vcpu->kvm->arch.sca;
- if (!kvm_s390_use_sca_entries())
+ if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized)
return;
clear_bit_inv(vcpu->vcpu_id, (unsigned long *)sca->mcn);
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call()
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (2 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:51 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 05/14] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
` (9 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
When cleaning up a UCONTROL VM, sca_clear_ext_call() will touch memory
outside of the allocated ESCA block, and UCONTROL VMs don't even use
ESCA.
Fix by not touching ESCA for UCONTROL VMs, and fence the
KVM_S390_INTERRUPT ioctl altogether.
Opportunistically add checks in sca_ext_call_pending() and
sca_inject_ext_call() to make sure UCONTROL VMs won't call those
functions ever.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Fixes: 7d43bafcff17 ("KVM: s390: Make provisions for ESCA utilization")
---
arch/s390/kvm/interrupt.c | 19 ++++++++++++++-----
arch/s390/kvm/kvm-s390.c | 3 +++
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 2acdff130fa6..6013f28e3461 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -45,13 +45,16 @@ static struct kvm_s390_gib *gib;
static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
{
struct esca_block *sca = vcpu->kvm->arch.sca;
- union esca_sigp_ctrl sigp_ctrl = sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+ union esca_sigp_ctrl sigp_ctrl;
if (!kvm_s390_test_cpuflags(vcpu, CPUSTAT_ECALL_PEND))
return 0;
+ if (KVM_BUG_ON(kvm_is_ucontrol(vcpu->kvm), vcpu->kvm))
+ return -EINVAL;
BUG_ON(!kvm_s390_use_sca_entries());
+ sigp_ctrl = sca->cpu[vcpu->vcpu_id].sigp_ctrl;
if (src_id)
*src_id = sigp_ctrl.scn;
@@ -60,13 +63,16 @@ static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
{
- struct esca_block *sca = vcpu->kvm->arch.sca;
- union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
union esca_sigp_ctrl old_val, new_val = {.scn = src_id, .c = 1};
+ struct esca_block *sca = vcpu->kvm->arch.sca;
+ union esca_sigp_ctrl *sigp_ctrl;
int expect, rc;
BUG_ON(!kvm_s390_use_sca_entries());
+ if (KVM_BUG_ON(kvm_is_ucontrol(vcpu->kvm), vcpu->kvm))
+ return -EINVAL;
+ sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
old_val = READ_ONCE(*sigp_ctrl);
old_val.c = 0;
@@ -84,10 +90,13 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
{
struct esca_block *sca = vcpu->kvm->arch.sca;
- union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+ union esca_sigp_ctrl *sigp_ctrl;
- if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized)
+ if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized || kvm_is_ucontrol(vcpu->kvm))
return;
+
+ /* Initialize after the above check, to prevent going out of bounds */
+ sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
WRITE_ONCE(sigp_ctrl->value, 0);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 58cec3703c2d..19ce7ebb83c5 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -2934,6 +2934,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
case KVM_S390_INTERRUPT: {
struct kvm_s390_interrupt s390int;
+ r = -EINVAL;
+ if (kvm_is_ucontrol(kvm))
+ break;
r = -EFAULT;
if (copy_from_user(&s390int, argp, sizeof(s390int)))
break;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 05/14] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (3 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:40 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 06/14] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
` (8 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
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: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
arch/s390/kvm/dat.c | 16 ++++++++++------
arch/s390/kvm/dat.h | 2 +-
arch/s390/kvm/kvm-s390.c | 16 ++++++++--------
arch/s390/kvm/priv.c | 5 +++--
4 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/arch/s390/kvm/dat.c b/arch/s390/kvm/dat.c
index ed4259d17629..171b61959908 100644
--- a/arch/s390/kvm/dat.c
+++ b/arch/s390/kvm/dat.c
@@ -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)
diff --git a/arch/s390/kvm/dat.h b/arch/s390/kvm/dat.h
index fad605305e05..141ee7b9f019 100644
--- a/arch/s390/kvm/dat.h
+++ b/arch/s390/kvm/dat.h
@@ -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);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 19ce7ebb83c5..de3cb6111bd4 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -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;
}
/**
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index ad0ddc433a73..ea5a99537346 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -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;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 06/14] KVM: s390: Fix race in __do_essa()
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (4 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 05/14] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:47 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
` (7 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
An unlikely race between __do_essa() and kvm_s390_vm_start_migration(),
kvm_s390_vm_stop_migration(), or dat_get_cmma() was possible.
Fix by locking kvm->slots_arch_lock. Since this is not a hot path, the
overhead of an additional mutex is negligible.
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
arch/s390/kvm/kvm-s390.c | 20 ++++++++++----------
arch/s390/kvm/priv.c | 5 +++--
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index de3cb6111bd4..24c3bfcd5db2 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -1219,8 +1219,8 @@ static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
/*
* Must be called with kvm->srcu held to avoid races on memslots, and with
- * kvm->slots_lock to avoid races with ourselves, kvm_s390_vm_stop_migration(),
- * and kvm_s390_get_cmma_bits().
+ * kvm->slots_arch_lock to avoid races with ourselves,
+ * kvm_s390_vm_stop_migration(), and kvm_s390_get_cmma_bits().
*/
static int kvm_s390_vm_start_migration(struct kvm *kvm)
{
@@ -1265,7 +1265,7 @@ static int kvm_s390_vm_start_migration(struct kvm *kvm)
}
/*
- * Must be called with kvm->slots_lock to avoid races with ourselves,
+ * Must be called with kvm->slots_arch_lock to avoid races with ourselves,
* kvm_s390_vm_start_migration() and kvm_s390_get_cmma_bits().
*/
static int kvm_s390_vm_stop_migration(struct kvm *kvm)
@@ -1300,7 +1300,9 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
{
int res = -ENXIO;
- mutex_lock(&kvm->slots_lock);
+ guard(srcu)(&kvm->srcu);
+ guard(mutex)(&kvm->slots_arch_lock);
+
switch (attr->attr) {
case KVM_S390_VM_MIGRATION_START:
res = kvm_s390_vm_start_migration(kvm);
@@ -1311,7 +1313,6 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
default:
break;
}
- mutex_unlock(&kvm->slots_lock);
return res;
}
@@ -3001,9 +3002,8 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
r = -EFAULT;
if (copy_from_user(&args, argp, sizeof(args)))
break;
- mutex_lock(&kvm->slots_lock);
- r = kvm_s390_get_cmma_bits(kvm, &args);
- mutex_unlock(&kvm->slots_lock);
+ scoped_guard(mutex, &kvm->slots_arch_lock)
+ r = kvm_s390_get_cmma_bits(kvm, &args);
if (!r) {
r = copy_to_user(argp, &args, sizeof(args));
if (r)
@@ -3017,9 +3017,9 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
r = -EFAULT;
if (copy_from_user(&args, argp, sizeof(args)))
break;
- mutex_lock(&kvm->slots_lock);
+ mutex_lock(&kvm->slots_arch_lock);
r = kvm_s390_set_cmma_bits(kvm, &args);
- mutex_unlock(&kvm->slots_lock);
+ mutex_unlock(&kvm->slots_arch_lock);
break;
}
case KVM_S390_PV_COMMAND: {
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index ea5a99537346..b1ba24c346ef 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -1261,8 +1261,9 @@ static int handle_essa(struct kvm_vcpu *vcpu)
/* Retry the ESSA instruction */
kvm_s390_retry_instr(vcpu);
} else {
- scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
- i = __do_essa(vcpu, orc);
+ scoped_guard(mutex, &vcpu->kvm->slots_arch_lock)
+ scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
+ i = __do_essa(vcpu, orc);
if (i < 0)
return i;
/* Account for the possible extra cbrl entry */
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (5 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 06/14] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:48 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
` (6 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
When a memslot is removed, all ptes that mapped the slot are cleared or
even deallocated. If this happens while the system is in migration
mode, and if cmma-dirty pages are removed, the cmma-dirty counter will
not reflect reality.
Fix by appropriately decrementing the cmma-dirty counter when removing
a memslot.
Opportunistically improve kvm_arch_commit_memory_region() to use
__free() for the struct kvm_s390_mmu_cache.
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
arch/s390/kvm/dat.c | 7 ++++++-
arch/s390/kvm/kvm-s390.c | 25 +++++++++++++++++++++++--
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/arch/s390/kvm/dat.c b/arch/s390/kvm/dat.c
index 171b61959908..3f2d6e8902d7 100644
--- a/arch/s390/kvm/dat.c
+++ b/arch/s390/kvm/dat.c
@@ -850,6 +850,7 @@ static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_wal
struct slot_priv *p = walk->priv;
union crste dummy = { .val = p->token };
union pte new_pte, pte = READ_ONCE(*ptep);
+ union pgste pgste;
new_pte = _PTE_TOK(dummy.tok.type, dummy.tok.par);
@@ -857,7 +858,11 @@ static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_wal
if (pte.val == new_pte.val)
return 0;
- dat_ptep_xchg(ptep, new_pte, gfn, walk->asce, false);
+ pgste = pgste_get_lock(ptep);
+ pgste = __dat_ptep_xchg(ptep, pgste, new_pte, gfn, walk->asce, false);
+ pgste.cmma_d = 0;
+ pgste_set_unlock(ptep, pgste);
+
return 0;
}
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 24c3bfcd5db2..c1984fe2f9a4 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -5809,14 +5809,30 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
return 0;
}
+static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ if (pgste.cmma_d) {
+ pgste.cmma_d = 0;
+ atomic64_dec(walk->priv);
+ }
+ pgste_set_unlock(ptep, pgste);
+ return 0;
+}
+
void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_memory_slot *old,
const struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
- struct kvm_s390_mmu_cache *mc = NULL;
+ const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
+ struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
int rc = 0;
+ guard(mutex)(&kvm->slots_arch_lock);
+
if (change == KVM_MR_FLAGS_ONLY)
return;
@@ -5827,6 +5843,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
}
scoped_guard(write_lock, &kvm->mmu_lock) {
+ if (kvm->arch.migration_mode && kvm->arch.use_cmma && old) {
+ _dat_walk_gfn_range(old->base_gfn, old->base_gfn + old->npages,
+ kvm->arch.gmap->asce, &ops, DAT_WALK_IGN_HOLES,
+ &kvm->arch.cmma_dirty_pages);
+ }
+
switch (change) {
case KVM_MR_DELETE:
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
@@ -5848,7 +5870,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
out:
if (rc)
pr_warn("failed to commit memory region\n");
- kvm_s390_free_mmu_cache(mc);
return;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (6 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:48 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 09/14] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
` (5 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
gmap_remove_child() needs to be called while holding the children_lock
of the parent gmap. This was not the case in the error handling path of
kvm_arch_vcpu_create() for UCONTROL guests.
Fix by adding the missing lock.
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/kvm/kvm-s390.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index c1984fe2f9a4..a234c2ab5fed 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3874,7 +3874,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
out_ucontrol_uninit:
if (kvm_is_ucontrol(vcpu->kvm)) {
+ spin_lock(&vcpu->kvm->arch.gmap->children_lock);
gmap_remove_child(vcpu->arch.gmap);
+ spin_unlock(&vcpu->kvm->arch.gmap->children_lock);
vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
}
out_free_sie_block:
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 09/14] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (7 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:44 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 10/14] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
` (4 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
The mmu cache is the first thing that is allocated in
kvm_arch_vcpu_create(), but in case of failure it was not freed.
Fix by freeing the mmu cache in case of failure.
Refactor kvm_arch_vcpu_create() to use scope-based cleanup instead of
gotos.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
---
arch/s390/kvm/kvm-s390.c | 40 ++++++++++++++++++----------------------
1 file changed, 18 insertions(+), 22 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index a234c2ab5fed..7395d7863670 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3799,21 +3799,21 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
return 0;
}
+DEFINE_FREE(sie_page, struct sie_page *, if (_T) free_page((unsigned long)(_T)))
+
int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
{
- struct sie_page *sie_page;
+ struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
+ struct sie_page *sie_page __free(sie_page) = NULL;
int rc;
BUILD_BUG_ON(sizeof(struct sie_page) != 4096);
- vcpu->arch.mc = kvm_s390_new_mmu_cache();
- if (!vcpu->arch.mc)
+ mc = kvm_s390_new_mmu_cache();
+ if (!mc)
return -ENOMEM;
sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL_ACCOUNT);
- if (!sie_page) {
- kvm_s390_free_mmu_cache(vcpu->arch.mc);
- vcpu->arch.mc = NULL;
+ if (!sie_page)
return -ENOMEM;
- }
vcpu->arch.sie_block = &sie_page->sie_block;
vcpu->arch.sie_block->itdba = virt_to_phys(&sie_page->itdb);
@@ -3855,10 +3855,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS;
if (kvm_is_ucontrol(vcpu->kvm)) {
- rc = -ENOMEM;
vcpu->arch.gmap = gmap_new_child(vcpu->kvm->arch.gmap, -1UL);
if (!vcpu->arch.gmap)
- goto out_free_sie_block;
+ return -ENOMEM;
}
VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%p, sie block at 0x%p",
@@ -3866,22 +3865,19 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
rc = kvm_s390_vcpu_setup(vcpu);
- if (rc)
- goto out_ucontrol_uninit;
+ if (rc) {
+ if (kvm_is_ucontrol(vcpu->kvm)) {
+ scoped_guard(spinlock, &vcpu->kvm->arch.gmap->children_lock)
+ gmap_remove_child(vcpu->arch.gmap);
+ vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
+ }
+ return rc;
+ }
+ vcpu->arch.mc = no_free_ptr(mc);
+ sie_page = NULL;
kvm_s390_update_topology_change_report(vcpu->kvm, 1);
return 0;
-
-out_ucontrol_uninit:
- if (kvm_is_ucontrol(vcpu->kvm)) {
- spin_lock(&vcpu->kvm->arch.gmap->children_lock);
- gmap_remove_child(vcpu->arch.gmap);
- spin_unlock(&vcpu->kvm->arch.gmap->children_lock);
- vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
- }
-out_free_sie_block:
- free_page((unsigned long)(vcpu->arch.sie_block));
- return rc;
}
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 10/14] KVM: s390: Return -EINTR if a signal is pending while faulting-in
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (8 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 09/14] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:53 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 11/14] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
` (3 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
If a fatal signal is pending while trying to fault-in a page, return
-EINTR instead of -EAGAIN.
Also fix unpack_one() to handle -EINTR properly.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Fixes: e907ae530133 ("KVM: s390: Add helper functions for fault handling")
---
arch/s390/kvm/faultin.c | 6 +++---
arch/s390/kvm/pv.c | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/s390/kvm/faultin.c b/arch/s390/kvm/faultin.c
index fee80047bd94..3cc45f7f5b2d 100644
--- a/arch/s390/kvm/faultin.c
+++ b/arch/s390/kvm/faultin.c
@@ -91,9 +91,9 @@ int kvm_s390_faultin_gfn(struct kvm_vcpu *vcpu, struct kvm *kvm, struct guest_fa
/* Access outside memory, addressing exception. */
if (is_noslot_pfn(f->pfn))
return PGM_ADDRESSING;
- /* Signal pending: try again. */
- if (f->pfn == KVM_PFN_ERR_SIGPENDING)
- return -EAGAIN;
+ /* Fatal signal pending: bail out. */
+ if (is_sigpending_pfn(f->pfn))
+ return -EINTR;
/* Check if it's read-only memory; don't try to actually handle that case. */
if (f->pfn == KVM_PFN_ERR_RO_FAULT)
return -EOPNOTSUPP;
diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c
index 1beacc841ca8..dc204b521052 100644
--- a/arch/s390/kvm/pv.c
+++ b/arch/s390/kvm/pv.c
@@ -809,7 +809,7 @@ static int unpack_one(struct kvm *kvm, unsigned long addr, u64 tweak,
return -EAGAIN;
}
- if (ret && ret != -EAGAIN)
+ if (ret && ret != -EAGAIN && ret != -EINTR)
KVM_UV_EVENT(kvm, 3, "PROTVIRT VM UNPACK: failed addr %llx with rc %x rrc %x",
uvcb.gaddr, *rc, *rrc);
return ret;
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 11/14] KVM: s390: Fix ordering when adding to SCA
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (9 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 10/14] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:54 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 12/14] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
` (2 subsequent siblings)
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
When adding a new vCPU to the SCA area, the validity bit in the MCN was
set before the pointer to the state description, potentially allowing
for a race.
Fix by setting the pointer before setting the bit.
Fixes: 14542a0a54c5 ("KVM: S390: Remove sca_lock")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
---
arch/s390/kvm/kvm-s390.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 7395d7863670..ba600c948887 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3484,8 +3484,8 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu)
if (!kvm_s390_use_sca_entries())
return;
+ WRITE_ONCE(sca->cpu[vcpu->vcpu_id].sda, virt_to_phys(vcpu->arch.sie_block));
set_bit_inv(vcpu->vcpu_id, (unsigned long *)sca->mcn);
- sca->cpu[vcpu->vcpu_id].sda = virt_to_phys(vcpu->arch.sie_block);
}
static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 12/14] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (10 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 11/14] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 16:52 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory Claudio Imbrenda
2026-07-30 16:27 ` [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region() Claudio Imbrenda
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
If creating a protected vCPU in kvm_s390_pv_create_cpu() fails,
kvm_s390_pv_destroy_cpu() was called, which checks whether the vCPU has
a PV handle and exits doing nothing otherwise. At that point, due to
not having created the protected vCPU, the PV handle will not be set,
and kvm_s390_pv_destroy_cpu() will do nothing, thus leaking the
allocated memory.
Fix by factoring out the code to free and reset a PV vCPU; call it from
kvm_s390_pv_destroy_cpu() and kvm_s390_pv_create_cpu().
Opportunistically fix the return value of kvm_s390_pv_destroy_cpu() in
case of errors: return -EIO instead if EIO.
Fixes: d4074324b07a ("KVM: s390: pv: avoid double free of sida page")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
---
arch/s390/kvm/pv.c | 41 +++++++++++++++++++++--------------------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c
index dc204b521052..b02e0159d3cd 100644
--- a/arch/s390/kvm/pv.c
+++ b/arch/s390/kvm/pv.c
@@ -244,6 +244,24 @@ static void kvm_s390_clear_pv_state(struct kvm *kvm)
kvm->arch.pv.stor_var = NULL;
}
+static void kvm_s390_pv_dispose_cpu(struct kvm_vcpu *vcpu, bool free_stor_base)
+{
+ if (free_stor_base)
+ free_pages(vcpu->arch.pv.stor_base, get_order(uv_info.guest_cpu_stor_len));
+ free_page((unsigned long)sida_addr(vcpu->arch.sie_block));
+ vcpu->arch.sie_block->pv_handle_cpu = 0;
+ vcpu->arch.sie_block->pv_handle_config = 0;
+ memset(&vcpu->arch.pv, 0, sizeof(vcpu->arch.pv));
+ vcpu->arch.sie_block->sdf = 0;
+ /*
+ * The sidad field (for sdf == 2) is now the gbea field (for sdf == 0).
+ * Use the reset value of gbea to avoid leaking the kernel pointer of
+ * the just freed sida.
+ */
+ vcpu->arch.sie_block->gbea = 1;
+ kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+}
+
int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
{
int cc;
@@ -258,24 +276,9 @@ int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
WARN_ONCE(cc, "protvirt destroy cpu failed rc %x rrc %x", *rc, *rrc);
/* Intended memory leak for something that should never happen. */
- if (!cc)
- free_pages(vcpu->arch.pv.stor_base,
- get_order(uv_info.guest_cpu_stor_len));
-
- free_page((unsigned long)sida_addr(vcpu->arch.sie_block));
- vcpu->arch.sie_block->pv_handle_cpu = 0;
- vcpu->arch.sie_block->pv_handle_config = 0;
- memset(&vcpu->arch.pv, 0, sizeof(vcpu->arch.pv));
- vcpu->arch.sie_block->sdf = 0;
- /*
- * The sidad field (for sdf == 2) is now the gbea field (for sdf == 0).
- * Use the reset value of gbea to avoid leaking the kernel pointer of
- * the just freed sida.
- */
- vcpu->arch.sie_block->gbea = 1;
- kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
+ kvm_s390_pv_dispose_cpu(vcpu, !cc);
- return cc ? EIO : 0;
+ return cc ? -EIO : 0;
}
int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
@@ -319,9 +322,7 @@ int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc)
uvcb.header.rrc);
if (cc) {
- u16 dummy;
-
- kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
+ kvm_s390_pv_dispose_cpu(vcpu, true);
return -EIO;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (11 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 12/14] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 17:02 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region() Claudio Imbrenda
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
When low on memory, kvm_arch_commit_memory_region() might not perform
the required action completely, and instead just print a warning and
return. This allows the VM to continue running with an inconsistent
state.
Fix by refilling the struct kvm_s390_mmu_cache and trying again. A true
failure only happens if the refill fails, or if the cache cannot be
allocated at all; in such case print a warning and kill the VM. Such a
failure cannot currently happen.
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
---
arch/s390/kvm/kvm-s390.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ba600c948887..035476ec7fbc 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -5827,7 +5827,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
{
const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
- int rc = 0;
+ int rc = -ENOMEM;
guard(mutex)(&kvm->slots_arch_lock);
@@ -5835,11 +5835,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
return;
mc = kvm_s390_new_mmu_cache();
- if (!mc) {
- rc = -ENOMEM;
+ if (!mc)
goto out;
- }
-
+retry:
scoped_guard(write_lock, &kvm->mmu_lock) {
if (kvm->arch.migration_mode && kvm->arch.use_cmma && old) {
_dat_walk_gfn_range(old->base_gfn, old->base_gfn + old->npages,
@@ -5862,11 +5860,17 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
case KVM_MR_FLAGS_ONLY:
break;
default:
+ rc = 0;
WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
}
}
+ if (rc == -ENOMEM) {
+ rc = kvm_s390_mmu_cache_topup(mc);
+ if (!rc)
+ goto retry;
+ }
out:
- if (rc)
+ if (KVM_BUG_ON(rc, kvm))
pr_warn("failed to commit memory region\n");
return;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region()
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
` (12 preceding siblings ...)
2026-07-30 16:27 ` [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory Claudio Imbrenda
@ 2026-07-30 16:27 ` Claudio Imbrenda
2026-07-30 17:01 ` sashiko-bot
13 siblings, 1 reply; 29+ messages in thread
From: Claudio Imbrenda @ 2026-07-30 16:27 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
Currently, when a memslot is changed, the changes in the page tables
are performed in kvm_arch_commit_memory_region(), which is assumed to
never fail, as it cannot return an error code.
If memory is tight, the allocation of page tables can fail, a warning
is printed, and the system is left in an inconsistent state.
Move the whole page table update into kvm_arch_prepare_memory_region()
instead. This function can fail and return an appropriate error code,
thus not leaving the system in an inconsistent state.
Fixes: 598841ca9919 ("[S390] use gmap address spaces for kvm guest images")
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
arch/s390/kvm/kvm-s390.c | 87 ++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 47 deletions(-)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 035476ec7fbc..668272dffa18 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -5761,11 +5761,30 @@ bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
}
/* Section: memory related */
+static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
+{
+ union pgste pgste;
+
+ pgste = pgste_get_lock(ptep);
+ if (pgste.cmma_d) {
+ pgste.cmma_d = 0;
+ atomic64_dec(walk->priv);
+ }
+ pgste_set_unlock(ptep, pgste);
+ return 0;
+}
+
int kvm_arch_prepare_memory_region(struct kvm *kvm,
const struct kvm_memory_slot *old,
struct kvm_memory_slot *new,
enum kvm_mr_change change)
{
+ const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
+ struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
+ int rc = -ENOMEM;
+
+ lockdep_assert_held(&kvm->slots_arch_lock);
+
if (kvm_is_ucontrol(kvm) && new && new->id < KVM_USER_MEM_SLOTS)
return -EINVAL;
@@ -5788,55 +5807,27 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
return -EINVAL;
}
- if (!kvm->arch.migration_mode)
- return 0;
-
- /*
- * Turn off migration mode when:
- * - userspace creates a new memslot with dirty logging off,
- * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
- * dirty logging is turned off.
- * Migration mode expects dirty page logging being enabled to store
- * its dirty bitmap.
- */
- if (change != KVM_MR_DELETE &&
- !(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
- WARN(kvm_s390_vm_stop_migration(kvm),
- "Failed to stop migration mode");
-
- return 0;
-}
-
-static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
-{
- union pgste pgste;
-
- pgste = pgste_get_lock(ptep);
- if (pgste.cmma_d) {
- pgste.cmma_d = 0;
- atomic64_dec(walk->priv);
+ if (kvm->arch.migration_mode) {
+ /*
+ * Turn off migration mode when:
+ * - userspace creates a new memslot with dirty logging off,
+ * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY)
+ * and dirty logging is turned off.
+ * Migration mode expects dirty page logging being enabled to
+ * store its dirty bitmap.
+ */
+ if (change != KVM_MR_DELETE &&
+ !(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
+ WARN(kvm_s390_vm_stop_migration(kvm),
+ "Failed to stop migration mode");
}
- pgste_set_unlock(ptep, pgste);
- return 0;
-}
-
-void kvm_arch_commit_memory_region(struct kvm *kvm,
- struct kvm_memory_slot *old,
- const struct kvm_memory_slot *new,
- enum kvm_mr_change change)
-{
- const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
- struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
- int rc = -ENOMEM;
-
- guard(mutex)(&kvm->slots_arch_lock);
if (change == KVM_MR_FLAGS_ONLY)
- return;
+ return 0;
mc = kvm_s390_new_mmu_cache();
if (!mc)
- goto out;
+ return -ENOMEM;
retry:
scoped_guard(write_lock, &kvm->mmu_lock) {
if (kvm->arch.migration_mode && kvm->arch.use_cmma && old) {
@@ -5869,10 +5860,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
if (!rc)
goto retry;
}
-out:
- if (KVM_BUG_ON(rc, kvm))
- pr_warn("failed to commit memory region\n");
- return;
+ return rc;
+}
+
+void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old,
+ const struct kvm_memory_slot *new, enum kvm_mr_change change)
+{
}
/**
--
2.55.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH v6 05/14] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
2026-07-30 16:27 ` [PATCH v6 05/14] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
@ 2026-07-30 16:40 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:40 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev
> 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: e38c884df921 ("KVM: s390: Switch to new gmap")
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=5
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 09/14] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
2026-07-30 16:27 ` [PATCH v6 09/14] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
@ 2026-07-30 16:44 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:44 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Vasily Gorbik, Heiko Carstens, kvm, linux-s390, Alexander Gordeev
> The mmu cache is the first thing that is allocated in
> kvm_arch_vcpu_create(), but in case of failure it was not freed.
>
> Fix by freeing the mmu cache in case of failure.
>
> Refactor kvm_arch_vcpu_create() to use scope-based cleanup instead of
> gotos.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=9
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 06/14] KVM: s390: Fix race in __do_essa()
2026-07-30 16:27 ` [PATCH v6 06/14] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
@ 2026-07-30 16:47 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:47 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Vasily Gorbik, linux-s390, Heiko Carstens, Alexander Gordeev, kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] System stall / SRCU stall warning due to holding `kvm->srcu` across a long-running page table walk.
--
--- Patch [6]: [PATCH v6 06/14] KVM: s390: Fix race in __do_essa() ---
commit 8a0e7e6fefae191da0effc8b1bcdd717dfb5216b
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix race in __do_essa()
This commit modifies the locking around KVM s390 migration and CMMA handling,
replacing slots_lock with slots_arch_lock to fix a race with __do_essa(). It
also adds a srcu guard to kvm_s390_vm_set_migration().
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index de3cb6111bd44..24c3bfcd5db26 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
> @@ -1300,7 +1300,9 @@ static int kvm_s390_vm_set_migration(struct kvm *kvm,
> {
> int res = -ENXIO;
>
> - mutex_lock(&kvm->slots_lock);
> + guard(srcu)(&kvm->srcu);
> + guard(mutex)(&kvm->slots_arch_lock);
> +
> switch (attr->attr) {
> case KVM_S390_VM_MIGRATION_START:
> res = kvm_s390_vm_start_migration(kvm);
[Severity: High]
Will holding kvm->srcu across the entire migration start/stop cause an SRCU
stall for large VMs?
Looking at kvm_s390_vm_start_migration(), it eventually calls
gmap_set_cmma_all_dirty() (and kvm_s390_vm_stop_migration() calls
gmap_set_cmma_all_clean()), which iterates over the entire guest address space:
kvm_s390_vm_set_migration()
kvm_s390_vm_start_migration()
gmap_set_cmma_all_dirty()
While the page table walk yields with cond_resched() to prevent soft lockups,
yielding inside an SRCU read-side critical section does not allow the SRCU
grace period to advance.
Could this stall the SRCU grace period and block concurrent memslot updates
across the system?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=6
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot
2026-07-30 16:27 ` [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
@ 2026-07-30 16:48 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:48 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Heiko Carstens, linux-s390, Alexander Gordeev, kvm, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Medium] Mixing goto-based error handling with scope-based cleanup (__free and guard) in the same function.
Pre-existing issues:
- [Critical] Silent ENOMEM failures in commit_memory_region leave stale guest page tables, causing host Use-After-Free.
- [High] KVM_MR_MOVE operations can exhaust the MMU cache (`mc`), leading to silent memslot corruption.
--
--- Patch [7]: [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot ---
commit fbfd75bf3afca84e6e947282c2cd405f559d2839
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: cmma: Fix dirty tracking when removing memslot
This patch updates memslot removal to appropriately decrement the
cmma-dirty counter to keep it accurate when the system is in migration
mode. It also updates kvm_arch_commit_memory_region() to use __free()
for the struct kvm_s390_mmu_cache.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 24c3bfcd5db26..c1984fe2f9a40 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
> @@ -5809,14 +5809,30 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
> return 0;
> }
>
> +static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
> +{
[ ... ]
> +}
> +
> void kvm_arch_commit_memory_region(struct kvm *kvm,
> struct kvm_memory_slot *old,
> const struct kvm_memory_slot *new,
> enum kvm_mr_change change)
> {
> - struct kvm_s390_mmu_cache *mc = NULL;
> + const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
> + struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
> int rc = 0;
>
> + guard(mutex)(&kvm->slots_arch_lock);
> +
[Severity: Medium]
Does this mix scope-based cleanup with goto-based error handling?
The patch adds __free() and guard() here, but kvm_arch_commit_memory_region()
still retains legacy goto-based error handling shortly after this:
mc = kvm_s390_new_mmu_cache();
if (!mc) {
rc = -ENOMEM;
goto out;
}
The cleanup guidelines in include/linux/cleanup.h state that a function
must use scope-based cleanup entirely or not at all, to prevent subtle
resource leaks when cleanup order (LIFO) is misunderstood.
[Severity: Critical]
This is a pre-existing issue, but can this silent ENOMEM failure leave stale
guest page tables?
If kvm_s390_new_mmu_cache() fails in the snippet above, the deletion of
guest page tables is skipped.
Since KVM's generic memslot management removes the memslot and allows host
userspace to unmap the backing memory, the guest's hardware page tables
(gmap) would retain valid PTE mappings to those physical pages, potentially
leading to a host use-after-free.
> if (change == KVM_MR_FLAGS_ONLY)
> return;
>
> @@ -5827,6 +5843,12 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> }
>
> scoped_guard(write_lock, &kvm->mmu_lock) {
> + if (kvm->arch.migration_mode && kvm->arch.use_cmma && old) {
> + _dat_walk_gfn_range(old->base_gfn, old->base_gfn + old->npages,
> + kvm->arch.gmap->asce, &ops, DAT_WALK_IGN_HOLES,
> + &kvm->arch.cmma_dirty_pages);
> + }
> +
> switch (change) {
> case KVM_MR_DELETE:
> rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
> @@ -5848,7 +5870,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> out:
> if (rc)
> pr_warn("failed to commit memory region\n");
> - kvm_s390_free_mmu_cache(mc);
> return;
> }
[Severity: High]
This is a pre-existing issue, but can a KVM_MR_MOVE operation exhaust the
MMU cache?
Looking at the KVM_MR_MOVE case in kvm_arch_commit_memory_region():
case KVM_MR_MOVE:
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
if (rc)
break;
fallthrough;
case KVM_MR_CREATE:
rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages);
dat_delete_slot() and dat_create_slot() are called sequentially without
replenishing the MMU cache (mc) in between.
If both operations require splitting large pages, the cache could be
exhausted, and dat_create_slot() might fail with -ENOMEM. The generic KVM
code would assume the move succeeded, but the new guest page tables would be
unmapped, leading to a guest crash on access.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=7
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
2026-07-30 16:27 ` [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
@ 2026-07-30 16:48 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:48 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Heiko Carstens, kvm, Alexander Gordeev, linux-s390, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The s390 MMU cache (`vcpu->arch.mc`) and its internally topped-up pages are permanently leaked on the error paths of `kvm_arch_vcpu_create()`.
--
--- Patch [8]: [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() ---
commit 84329d883b130f6a53d6ec86765dba1245a95998
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
gmap_remove_child() needs to be called while holding the children_lock
of the parent gmap. This was not the case in the error handling path of
kvm_arch_vcpu_create() for UCONTROL guests.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index c1984fe2f9a40..a234c2ab5fed5 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3874,7 +3874,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
>
> out_ucontrol_uninit:
> if (kvm_is_ucontrol(vcpu->kvm)) {
> + spin_lock(&vcpu->kvm->arch.gmap->children_lock);
> gmap_remove_child(vcpu->arch.gmap);
> + spin_unlock(&vcpu->kvm->arch.gmap->children_lock);
> vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
> }
> out_free_sie_block:
[Severity: High]
This is a pre-existing issue, but does this error path permanently leak the
s390 MMU cache and its internally topped-up pages?
When an error occurs during kvm_arch_vcpu_create(), such as a failure in
gmap_new_child() or kvm_s390_vcpu_setup(), the error path jumps to
out_free_sie_block. This frees the sie_page but fails to call
kvm_s390_free_mmu_cache() for vcpu->arch.mc.
Since userspace can repeatedly invoke the KVM_CREATE_VCPU ioctl and force it
to fail (for example, by exhausting cgroup memory limits to trigger an
-ENOMEM), could this result in a permanent kernel memory leak triggerable
from userspace?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=8
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference
2026-07-30 16:27 ` [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
@ 2026-07-30 16:50 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:50 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: kvm, Alexander Gordeev, linux-s390, Vasily Gorbik, Heiko Carstens
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The patch implements an architecture-specific workaround to fix a generic KVM race condition instead of addressing the root cause by deferring fd_install().
--
--- Patch [1]: [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference ---
commit 403acc4eca694d221f980de53cd9d5235694b0bf
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix unlikely NULL gmap dereference
This commit fixes a race condition where a malicious userspace program
can start a newly created vCPU before kvm_arch_vcpu_postcreate() finishes.
It resolves this by tracking the initialization status with a new flag.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 150b5dd2170e2..f86b4b0b356f4 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
> @@ -3613,6 +3613,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
> if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0 ||
> vcpu->kvm->arch.user_operexec)
> vcpu->arch.sie_block->ictl |= ICTL_OPEREXC;
> +
> + /* Pairs with smp_load_acquire() in kvm_arch_vcpu_ioctl_run() and kvm_arch_vcpu_ioctl() */
> + smp_store_release(&vcpu->arch.initialized, true);
[Severity: Medium]
Could this regression be addressed in the generic KVM code rather than
adding an architecture-specific workaround here?
The race occurs because virt/kvm/kvm_main.c:kvm_vm_ioctl_create_vcpu()
exposes the file descriptor to userspace before postcreate completes:
virt/kvm/kvm_main.c:kvm_vm_ioctl_create_vcpu() {
...
r = create_vcpu_fd(vcpu);
...
kvm_arch_vcpu_postcreate(vcpu);
...
}
Since create_vcpu_fd() installs the file descriptor, userspace can
immediately guess or observe the fd and race to call KVM_RUN or other
ioctls while kvm_arch_vcpu_postcreate() is still running.
Could we fix this generically by splitting anon_inode_getfd() into
get_unused_fd_flags() and anon_inode_getfile() during fd creation,
and then deferring fd_install() until after kvm_arch_vcpu_postcreate()
completes?
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call()
2026-07-30 16:27 ` [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
@ 2026-07-30 16:51 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:51 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: linux-s390, Vasily Gorbik, Alexander Gordeev, kvm, Heiko Carstens
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The patch introduces a KVM_BUG_ON() in sca_inject_ext_call() and sca_ext_call_pending() to assert that UCONTROL VMs never reach these functions. However, userspace can easily reach them because the patch fails to fence VCPU-level ioctls and memory-mapped sie_block access.
--
--- Patch [4]: [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call() ---
commit b27149eacddb40ae95c3a0b8dc6d91809e9ace8b
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: ucontrol: Fix sca_clear_ext_call()
When cleaning up a UCONTROL VM, sca_clear_ext_call() will touch memory
outside of the allocated ESCA block, and UCONTROL VMs don't even use
ESCA. This patch fixes the issue by not touching ESCA for UCONTROL VMs
and fencing the VM-level KVM_S390_INTERRUPT ioctl. It also adds checks
to prevent sca_ext_call_pending() and sca_inject_ext_call() from running
on UCONTROL VMs.
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index 2acdff130fa6c..6013f28e3461f 100644
> --- a/arch/s390/kvm/interrupt.c
> +++ b/arch/s390/kvm/interrupt.c
> @@ -45,13 +45,16 @@ static struct kvm_s390_gib *gib;
> static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
> {
> struct esca_block *sca = vcpu->kvm->arch.sca;
> - union esca_sigp_ctrl sigp_ctrl = sca->cpu[vcpu->vcpu_id].sigp_ctrl;
> + union esca_sigp_ctrl sigp_ctrl;
>
> if (!kvm_s390_test_cpuflags(vcpu, CPUSTAT_ECALL_PEND))
> return 0;
>
> + if (KVM_BUG_ON(kvm_is_ucontrol(vcpu->kvm), vcpu->kvm))
> + return -EINVAL;
[Severity: Medium]
Is it possible for userspace to trigger this KVM_BUG_ON and cause a host
kernel warning splat?
For UCONTROL VMs, the sie_block is directly memory-mapped to userspace at
KVM_S390_SIE_PAGE_OFFSET. If userspace manually sets the CPUSTAT_ECALL_PEND
bit in sie_block->cpuflags and executes KVM_RUN, wouldn't it reach this
check during pending interrupt evaluation?
> BUG_ON(!kvm_s390_use_sca_entries());
[ ... ]
> @@ -60,13 +63,16 @@ static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
>
> static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
> {
> - struct esca_block *sca = vcpu->kvm->arch.sca;
> - union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
> union esca_sigp_ctrl old_val, new_val = {.scn = src_id, .c = 1};
> + struct esca_block *sca = vcpu->kvm->arch.sca;
> + union esca_sigp_ctrl *sigp_ctrl;
> int expect, rc;
>
> BUG_ON(!kvm_s390_use_sca_entries());
> + if (KVM_BUG_ON(kvm_is_ucontrol(vcpu->kvm), vcpu->kvm))
> + return -EINVAL;
[Severity: Medium]
Could this KVM_BUG_ON be reached via the VCPU-level ioctls?
While this patch fences the VM-level KVM_S390_INTERRUPT ioctl, it appears
that the VCPU-level KVM_S390_IRQ and KVM_S390_INTERRUPT ioctls in
kvm_arch_vcpu_unlocked_ioctl() remain unfenced for UCONTROL VMs.
If userspace calls one of these VCPU ioctls with KVM_S390_INT_EXTERNAL_CALL,
would it flow through kvm_s390_inject_vcpu() to sca_inject_ext_call() and hit
this assertion?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=4
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 12/14] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
2026-07-30 16:27 ` [PATCH v6 12/14] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
@ 2026-07-30 16:52 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:52 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Vasily Gorbik, Alexander Gordeev, kvm, linux-s390, Heiko Carstens
> If creating a protected vCPU in kvm_s390_pv_create_cpu() fails,
> kvm_s390_pv_destroy_cpu() was called, which checks whether the vCPU has
> a PV handle and exits doing nothing otherwise. At that point, due to
> not having created the protected vCPU, the PV handle will not be set,
> and kvm_s390_pv_destroy_cpu() will do nothing, thus leaking the
> allocated memory.
>
> Fix by factoring out the code to free and reset a PV vCPU; call it from
> kvm_s390_pv_destroy_cpu() and kvm_s390_pv_create_cpu().
>
> Opportunistically fix the return value of kvm_s390_pv_destroy_cpu() in
> case of errors: return -EIO instead if EIO.
>
> Fixes: d4074324b07a ("KVM: s390: pv: avoid double free of sida page")
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=12
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 10/14] KVM: s390: Return -EINTR if a signal is pending while faulting-in
2026-07-30 16:27 ` [PATCH v6 10/14] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
@ 2026-07-30 16:53 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:53 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Heiko Carstens, linux-s390, Alexander Gordeev, kvm, Vasily Gorbik
> If a fatal signal is pending while trying to fault-in a page, return
> -EINTR instead of -EAGAIN.
>
> Also fix unpack_one() to handle -EINTR properly.
>
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=10
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 11/14] KVM: s390: Fix ordering when adding to SCA
2026-07-30 16:27 ` [PATCH v6 11/14] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
@ 2026-07-30 16:54 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:54 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Alexander Gordeev, linux-s390, Vasily Gorbik, Heiko Carstens, kvm
> When adding a new vCPU to the SCA area, the validity bit in the MCN was
> set before the pointer to the state description, potentially allowing
> for a race.
>
> Fix by setting the pointer before setting the bit.
>
> Fixes: 14542a0a54c5 ("KVM: S390: Remove sca_lock")
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=11
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
2026-07-30 16:27 ` [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
@ 2026-07-30 16:55 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 16:55 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: linux-s390, kvm, Vasily Gorbik, Alexander Gordeev, Heiko Carstens
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Unprivileged local memory corruption via `sca_dispose(NULL)` leading to freeing physical pages 1, 2, and 3.
- [High] Memory leak of `vcpu->arch.mc` in the error path of `kvm_arch_vcpu_create()`.
- [High] Missing lock acquisition when removing a child gmap in the vCPU creation error path.
- [High] When `uv_call` fails during `kvm_s390_pv_create_cpu()`, newly allocated `stor_base` and `sida_addr` pages are permanently leaked.
--
--- Patch [2]: [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() ---
commit b2abac5b0352ced2b250d10ad5dfc60b18cae87c
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
In some cases kvm_s390_vcpu_unsetup_cmma() can be called with a 0
cbrlo; in such cases, if running with V != R, free_page() will attempt
to free physical page 0.
Fix by freeing cbrlo only if it's non-zero.
Fixes: b31605c12f4e ("KVM: s390: make cmma usage conditionally")
Fixes: 29b40f105ec8 ("KVM: s390: protvirt: Add initial vm and cpu lifecycle handling")
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index f86b4b0b356f4..9ec5833a09732 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3677,7 +3677,8 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
>
> void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu)
> {
> - free_page((unsigned long)phys_to_virt(vcpu->arch.sie_block->cbrlo));
> + if (vcpu->arch.sie_block->cbrlo)
> + free_page((unsigned long)phys_to_virt(vcpu->arch.sie_block->cbrlo));
> vcpu->arch.sie_block->cbrlo = 0;
> }
While reviewing this code, a few other things were noticed nearby.
arch/s390/kvm/kvm-s390.c:kvm_arch_vcpu_create() {
[ ... ]
out_ucontrol_uninit:
if (kvm_is_ucontrol(vcpu->kvm)) {
gmap_remove_child(vcpu->arch.gmap);
[Severity: High]
This is a pre-existing issue, but is it possible we are missing a lock here?
In kvm_arch_vcpu_create(), if a ucontrol VM's vCPU setup fails, it calls
gmap_remove_child(vcpu->arch.gmap).
The gmap_remove_child() function expects the parent gmap's children_lock to
be held and concurrently modifies the parent gmap's children list. However,
this error path appears to omit acquiring the children_lock.
Could this lead to a data race and list corruption?
vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
}
out_free_sie_block:
free_page((unsigned long)(vcpu->arch.sie_block));
return rc;
}
[Severity: High]
This is a pre-existing issue, but what happens to the vcpu->arch.mc memory
when we take this error path?
When an error occurs in kvm_arch_vcpu_create() after vcpu->arch.mc
allocation, the code jumps to out_ucontrol_uninit and out_free_sie_block.
While it frees the sie_block and removes the gmap child, it seems to never
free the memory allocated by kvm_s390_new_mmu_cache(vcpu->arch.mc).
Can userspace repeatedly trigger vCPU creation failures to leak memory and
cause a local denial of service?
arch/s390/kvm/kvm-s390.c:kvm_arch_init_vm() {
[ ... ]
out_err:
free_page((unsigned long)kvm->arch.sie_page2);
debug_unregister(kvm->arch.dbf);
sca_dispose(kvm);
[ ... ]
}
arch/s390/kvm/kvm-s390.c:sca_dispose() {
free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
kvm->arch.sca = NULL;
}
[Severity: Critical]
This is a pre-existing issue, but is there a risk of memory corruption here?
In kvm_arch_init_vm(), if VM creation fails early, the code jumps to out_err
before kvm->arch.sca is allocated.
Since the kvm structure is zero-allocated, kvm->arch.sca is NULL.
The sca_dispose() function calls
free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca)). The size of
struct esca_block is roughly 16KB.
The free_pages_exact(virt, size) function loops from addr = virt to
addr + PAGE_ALIGN(size), incrementing by PAGE_SIZE, and calls
free_page(addr).
For virt == NULL, it iterates through addresses 0, 4096, 8192, and 12288.
While free_page(0) is safely ignored, free_page(4096) translates to
__free_pages(virt_to_page(4096), 0) and incorrectly frees host physical pages
1, 2, and 3 into the buddy allocator.
Can an unprivileged user trigger this trivially by calling
ioctl(KVM_CREATE_VM, 1)?
arch/s390/kvm/pv.c:kvm_s390_pv_create_cpu() {
[ ... ]
cc = uv_call(0, (u64)&uvcb);
[ ... ]
if (cc) {
u16 dummy;
kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
return -EIO;
}
[ ... ]
}
arch/s390/kvm/pv.c:kvm_s390_pv_destroy_cpu() {
int cc;
if (!kvm_s390_pv_cpu_get_handle(vcpu))
return 0;
[ ... ]
}
[Severity: High]
This is a pre-existing issue, but does this error handling permanently leak
the newly allocated stor_base and sida_addr pages?
The kvm_s390_pv_create_cpu() function allocates vcpu->arch.pv.stor_base
and sida_addr. If uv_call fails, it jumps to error handling which
calls kvm_s390_pv_destroy_cpu(vcpu).
However, kvm_s390_pv_destroy_cpu() begins with an early return:
if (!kvm_s390_pv_cpu_get_handle(vcpu)) return 0;
Because vcpu->arch.pv.handle is only set upon successful uv_call completion,
the handle is 0 here. Thus, the destruction routine does nothing and bypasses
the free_pages() blocks entirely.
Could a compromised or malicious userspace trigger failures in uv_call to
repeatedly leak host memory?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=2
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region()
2026-07-30 16:27 ` [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region() Claudio Imbrenda
@ 2026-07-30 17:01 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 17:01 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Heiko Carstens, linux-s390, kvm, Vasily Gorbik, Alexander Gordeev
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] Moving DAT page table modifications and migration state updates to `kvm_arch_prepare_memory_region()` without rollback logic permanently corrupts guest state and causes an infinite loop (host DoS) on error paths.
--
--- Patch [14]: [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region() ---
commit 99c3a9b6f800205c1388216366b06b3eef1e58f0
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region()
This commit moves the whole page table update logic from
kvm_arch_commit_memory_region() to kvm_arch_prepare_memory_region().
This allows the memory allocation failures during DAT table updates to be
propagated to userspace as errors rather than leaving the system in an
inconsistent state.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 035476ec7fbc3..668272dffa18b 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
> @@ -5788,55 +5807,27 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
[ ... ]
> +retry:
> + scoped_guard(write_lock, &kvm->mmu_lock) {
> + if (kvm->arch.migration_mode && kvm->arch.use_cmma && old) {
> + _dat_walk_gfn_range(old->base_gfn, old->base_gfn + old->npages,
> + kvm->arch.gmap->asce, &ops, DAT_WALK_IGN_HOLES,
> + &kvm->arch.cmma_dirty_pages);
> + }
> +
> + switch (change) {
> + case KVM_MR_DELETE:
> + rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
> + break;
> + case KVM_MR_MOVE:
> + rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
> + if (rc)
> + break;
> + fallthrough;
> + case KVM_MR_CREATE:
> + rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages);
> + break;
> + case KVM_MR_FLAGS_ONLY:
> + break;
> + default:
> + rc = 0;
> + WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
> + }
> + }
> + if (rc == -ENOMEM) {
> + rc = kvm_s390_mmu_cache_topup(mc);
> + if (!rc)
> + goto retry;
> + }
> + return rc;
[Severity: Critical]
If kvm_s390_mmu_cache_topup() fails here and returns -ENOMEM, does this leave
the DAT modifications intact without any rollback?
If this returns an error, the KVM core will catch it and restore the active
memslot metadata:
virt/kvm/kvm_main.c:kvm_set_memslot() {
...
if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
kvm_activate_memslot(kvm, invalid_slot, old);
kfree(invalid_slot);
}
...
}
Will this cause KVM core to be permanently desynchronized from the hardware
DAT tree, leaving program check holes in the DAT tree?
If the guest subsequently accesses this out-of-sync memslot, can it trigger an
infinite loop in the fault handler?
Looking at kvm_s390_faultin_gfn(), if the memslot still exists in KVM core,
it resolves the PFN and calls gmap_link(). Because the DAT tree still has the
hole, gmap_link() returns -EAGAIN. The fault handler might loop infinitely:
arch/s390/kvm/faultin.c:kvm_s390_faultin_gfn() {
...
while (rc == -EAGAIN) {
...
if (!mmu_invalidate_retry_gfn(kvm, inv_seq, f->gfn)) {
f->valid = true;
rc = gmap_link(mc, kvm->arch.gmap, f, slot);
}
...
}
Could an unprivileged userspace process under memory pressure intentionally
trigger this error path and cause a host denial of service?
> +}
> +
> +void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old,
> + const struct kvm_memory_slot *new, enum kvm_mr_change change)
> +{
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=14
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory
2026-07-30 16:27 ` [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory Claudio Imbrenda
@ 2026-07-30 17:02 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 17:02 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Vasily Gorbik, Alexander Gordeev, linux-s390, Heiko Carstens, kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unprivileged userspace can trigger a host-side WARN_ON_ONCE via KVM_BUG_ON by exhausting memory cgroup limits.
--
--- Patch [13]: [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory ---
commit c04a67c8bae206347441b13dff0d06941031c158
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory
When low on memory, kvm_arch_commit_memory_region() might not perform
the required action completely. The patch attempts to fix this by refilling
the MMU cache and retrying, using KVM_BUG_ON if it still fails.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index ba600c9488871..035476ec7fbc3 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
> @@ -5862,11 +5860,17 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> case KVM_MR_FLAGS_ONLY:
> break;
> default:
> + rc = 0;
> WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
> }
> }
> + if (rc == -ENOMEM) {
> + rc = kvm_s390_mmu_cache_topup(mc);
> + if (!rc)
> + goto retry;
> + }
> out:
> - if (rc)
> + if (KVM_BUG_ON(rc, kvm))
[Severity: High]
Could this KVM_BUG_ON() be triggered by an unprivileged host-userspace
process exhausting its memory cgroup limit?
If kvm_s390_new_mmu_cache() fails to allocate memory (for example, due to a
memcg limit restricting its GFP_KERNEL_ACCOUNT allocation), the function jumps
to the out label with rc set to -ENOMEM.
Passing this error to KVM_BUG_ON() executes a WARN_ON_ONCE. If the host has
panic_on_warn enabled, this would crash the system, potentially allowing a
host-side denial of service directly reachable from unprivileged userspace.
Is it possible to use pr_warn_once() or a similar logging mechanism here to
avoid assertions on userspace-driven inputs?
> pr_warn("failed to commit memory region\n");
> return;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=13
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error
2026-07-30 16:27 ` [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
@ 2026-07-30 17:04 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-07-30 17:04 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing ucontrol checks in ESCA handling lead to out-of-bounds memory accesses for KVM_VM_UCONTROL VMs.
- [High] Memory leak of `vcpu->arch.mc` on error paths in `kvm_arch_vcpu_create()`.
--
--- Patch [3]: [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error ---
commit 0972b46b8d10201faec4d5ded093d7c4cc013c9b
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix overclearing ESCA in case of error
If an attempt is made to create a vCPU with an already existing ID,
the duplicated vCPU will be destroyed. When destroying a vCPU, its
ESCA entry will be cleared. In the above scenario, the spurious
duplicate vCPU is destroyed, but the ESCA entry corresponding to the
original vCPU is cleared.
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index 9e3e6b0d72ad6..2acdff130fa6c 100644
> --- a/arch/s390/kvm/interrupt.c
> +++ b/arch/s390/kvm/interrupt.c
> @@ -86,7 +86,7 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
> struct esca_block *sca = vcpu->kvm->arch.sca;
> union esca_sigp_ctrl *sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
>
> - if (!kvm_s390_use_sca_entries())
> + if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized)
[Severity: High]
This is a pre-existing issue, but missing ucontrol checks in ESCA handling
can lead to out-of-bounds memory accesses for KVM_VM_UCONTROL VMs.
If a user creates a KVM_VM_S390_UCONTROL VM (requires CAP_SYS_ADMIN), skips
sca_can_add_vcpu() limit checks during vCPU creation, and successfully
initializes vCPU IDs up to 254 (above the ESCA array limit of 248), does this
allow out-of-bounds reads and writes?
For example, when injecting KVM_S390_INT_EXTERNAL_CALL or resetting the vCPU,
sca_clear_ext_call() unconditionally writes 0:
arch/s390/kvm/interrupt.c:sca_clear_ext_call() {
...
WRITE_ONCE(sigp_ctrl->value, 0);
}
Similarly, sca_inject_ext_call() performs an out-of-bounds cmpxchg write:
arch/s390/kvm/interrupt.c:sca_inject_ext_call() {
...
rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
}
Could this corrupt the kernel memory adjacent to the esca_block pages for
vCPU IDs >= 248?
> return;
> kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
[ ... ]
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 9ec5833a09732..58cec3703c2d5 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
[Severity: High]
This is a pre-existing issue, but does kvm_arch_vcpu_create() in
arch/s390/kvm/kvm-s390.c leak the MMU cache allocation on error paths?
If a subsequent allocation fails after kvm_s390_new_mmu_cache() assigns the
cache to vcpu->arch.mc, the function jumps to out_free_sie_block and returns
an error without freeing the MMU cache:
arch/s390/kvm/kvm-s390.c:kvm_arch_vcpu_create() {
...
out_free_sie_block:
free_page((unsigned long)(vcpu->arch.sie_block));
return rc;
}
Since kvm_vm_ioctl_create_vcpu() decrements kvm->created_vcpus and frees the
vCPU struct but does not call kvm_arch_vcpu_destroy() on this error path,
would vcpu->arch.mc be permanently leaked?
Can an unprivileged user repeatedly attempt to create a vCPU and force memory
allocation failures to cause an unbounded memory leak?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260730162714.133327-1-imbrenda@linux.ibm.com?part=3
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-07-30 17:04 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 16:27 [PATCH v6 00/14] KVM: s390: Misc fixes Claudio Imbrenda
2026-07-30 16:27 ` [PATCH v6 01/14] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
2026-07-30 16:50 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 02/14] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
2026-07-30 16:55 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 03/14] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
2026-07-30 17:04 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 04/14] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
2026-07-30 16:51 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 05/14] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
2026-07-30 16:40 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 06/14] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
2026-07-30 16:47 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 07/14] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
2026-07-30 16:48 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 08/14] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
2026-07-30 16:48 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 09/14] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
2026-07-30 16:44 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 10/14] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
2026-07-30 16:53 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 11/14] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
2026-07-30 16:54 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 12/14] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
2026-07-30 16:52 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 13/14] KVM: s390: Fix kvm_arch_commit_memory_region() when low on memory Claudio Imbrenda
2026-07-30 17:02 ` sashiko-bot
2026-07-30 16:27 ` [PATCH v6 14/14] KVM: s390: Move DAT table updates to kvm_arch_prepare_memory_region() Claudio Imbrenda
2026-07-30 17:01 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.