* [PATCH v8 01/13] KVM: s390: Fix unlikely NULL gmap dereference
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 12:55 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
` (11 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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] 34+ messages in thread* Re: [PATCH v8 01/13] KVM: s390: Fix unlikely NULL gmap dereference
2026-08-03 12:40 ` [PATCH v8 01/13] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
@ 2026-08-03 12:55 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 12:55 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev, kvm
> 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>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
2026-08-03 12:40 ` [PATCH v8 01/13] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 12:55 ` sashiko-bot
` (2 more replies)
2026-08-03 12:40 ` [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
` (10 subsequent siblings)
12 siblings, 3 replies; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 UTC (permalink / raw)
To: linux-kernel
Cc: kvm, linux-s390, borntraeger, frankja, david, seiden, nrb,
schlameuss, gra
If VM creation fails early in kvm_arch_init_vm(), the cleanup code
tries to free up the SCA, even though the address is 0. Due to using
free_pages_exact(), only the first page is skipped, accidentally
freeing pages 1, 2, and 3.
Fix by checking whether the pointer is NULL before attempting to free
the SCA in sca_dispose().
Fixes: e72753ed1267 ("KVM: s390: Use ESCA instead of BSCA at VM init")
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..1b3290a5ad1a 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3247,7 +3247,8 @@ static void kvm_s390_crypto_init(struct kvm *kvm)
static void sca_dispose(struct kvm *kvm)
{
- free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
+ if (kvm->arch.sca)
+ free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
kvm->arch.sca = NULL;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated
2026-08-03 12:40 ` [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
@ 2026-08-03 12:55 ` sashiko-bot
2026-08-03 14:08 ` Christian Borntraeger
2026-08-03 14:13 ` Janosch Frank
2 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 12:55 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Heiko Carstens, Vasily Gorbik, linux-s390, kvm, Alexander Gordeev
> If VM creation fails early in kvm_arch_init_vm(), the cleanup code
> tries to free up the SCA, even though the address is 0. Due to using
> free_pages_exact(), only the first page is skipped, accidentally
> freeing pages 1, 2, and 3.
>
> Fix by checking whether the pointer is NULL before attempting to free
> the SCA in sca_dispose().
>
> Fixes: e72753ed1267 ("KVM: s390: Use ESCA instead of BSCA at VM init")
> 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/20260803124040.126471-1-imbrenda@linux.ibm.com?part=2
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated
2026-08-03 12:40 ` [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
2026-08-03 12:55 ` sashiko-bot
@ 2026-08-03 14:08 ` Christian Borntraeger
2026-08-03 14:13 ` Janosch Frank
2 siblings, 0 replies; 34+ messages in thread
From: Christian Borntraeger @ 2026-08-03 14:08 UTC (permalink / raw)
To: Claudio Imbrenda, linux-kernel
Cc: kvm, linux-s390, frankja, david, seiden, nrb, schlameuss, gra
Am 03.08.26 um 14:40 schrieb Claudio Imbrenda:
> If VM creation fails early in kvm_arch_init_vm(), the cleanup code
> tries to free up the SCA, even though the address is 0. Due to using
> free_pages_exact(), only the first page is skipped, accidentally
> freeing pages 1, 2, and 3.
>
> Fix by checking whether the pointer is NULL before attempting to free
> the SCA in sca_dispose().
>
> Fixes: e72753ed1267 ("KVM: s390: Use ESCA instead of BSCA at VM init")
> Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@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..1b3290a5ad1a 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3247,7 +3247,8 @@ static void kvm_s390_crypto_init(struct kvm *kvm)
>
> static void sca_dispose(struct kvm *kvm)
> {
> - free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
> + if (kvm->arch.sca)
> + free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
> kvm->arch.sca = NULL;
> }
>
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated
2026-08-03 12:40 ` [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
2026-08-03 12:55 ` sashiko-bot
2026-08-03 14:08 ` Christian Borntraeger
@ 2026-08-03 14:13 ` Janosch Frank
2 siblings, 0 replies; 34+ messages in thread
From: Janosch Frank @ 2026-08-03 14:13 UTC (permalink / raw)
To: Claudio Imbrenda, linux-kernel
Cc: kvm, linux-s390, borntraeger, david, seiden, nrb, schlameuss, gra
On 8/3/26 14:40, Claudio Imbrenda wrote:
> If VM creation fails early in kvm_arch_init_vm(), the cleanup code
> tries to free up the SCA, even though the address is 0. Due to using
> free_pages_exact(), only the first page is skipped, accidentally
> freeing pages 1, 2, and 3.
>
> Fix by checking whether the pointer is NULL before attempting to free
> the SCA in sca_dispose().
>
> Fixes: e72753ed1267 ("KVM: s390: Use ESCA instead of BSCA at VM init")
> 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..1b3290a5ad1a 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3247,7 +3247,8 @@ static void kvm_s390_crypto_init(struct kvm *kvm)
>
> static void sca_dispose(struct kvm *kvm)
> {
> - free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
> + if (kvm->arch.sca)
> + free_pages_exact(kvm->arch.sca, sizeof(*kvm->arch.sca));
> kvm->arch.sca = NULL;
> }
>
uh, right, there's no null check in free_pages_exact()
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
2026-08-03 12:40 ` [PATCH v8 01/13] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
2026-08-03 12:40 ` [PATCH v8 02/13] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:19 ` sashiko-bot
2026-08-03 14:30 ` Janosch Frank
2026-08-03 12:40 ` [PATCH v8 04/13] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
` (9 subsequent siblings)
12 siblings, 2 replies; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 1b3290a5ad1a..9be27db0a21e 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3678,7 +3678,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] 34+ messages in thread* Re: [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
2026-08-03 12:40 ` [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
@ 2026-08-03 13:19 ` sashiko-bot
2026-08-03 14:30 ` Janosch Frank
1 sibling, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 13:19 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Alexander Gordeev, kvm, Vasily Gorbik, Heiko Carstens, linux-s390
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] The MMU cache (`vcpu->arch.mc`) is permanently leaked when `kvm_arch_vcpu_create()` fails during vCPU initialization.
- [High] Protected vCPU creation failure leaks `pv.stor_base` and `sidad` pages.
--
--- Patch [3]: [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() ---
commit 17f441be24aaabde7dd38b196f4dba98cf6e898d
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.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 1b3290a5ad1ae..9be27db0a21e6 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3678,7 +3678,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;
> }
[Severity: High]
This isn't a bug introduced by this patch, but it looks like the MMU cache
(vcpu->arch.mc) might be permanently leaked when kvm_arch_vcpu_create() fails
during vCPU initialization.
kvm_arch_vcpu_create() allocates memory for vcpu->arch.mc via
kvm_s390_new_mmu_cache(). If a subsequent initialization step fails, the error
paths free vcpu->arch.gmap and vcpu->arch.sie_block, but appear to omit
calling kvm_s390_free_mmu_cache(vcpu->arch.mc):
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);
vcpu->arch.gmap = gmap_put(vcpu->arch.gmap);
}
out_free_sie_block:
free_page((unsigned long)(vcpu->arch.sie_block));
return rc;
}
Since the KVM core does not call kvm_arch_vcpu_destroy() when
kvm_arch_vcpu_create() returns an error, could this leak the MMU cache pages
and allow a local user to exhaust kernel memory?
[Severity: High]
This is a pre-existing issue, but I noticed another potential leak in
kvm_s390_pv_create_cpu().
When creating a protected vCPU, pages are allocated for
vcpu->arch.pv.stor_base and the sida_addr. If the ultravisor call uv_call()
fails, the code attempts cleanup using kvm_s390_pv_destroy_cpu():
arch/s390/kvm/pv.c:kvm_s390_pv_create_cpu() {
...
if (cc) {
u16 dummy;
kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
return -EIO;
}
/* Output */
vcpu->arch.pv.handle = uvcb.cpu_handle;
...
}
However, kvm_s390_pv_destroy_cpu() begins with a check for the handle:
if (!kvm_s390_pv_cpu_get_handle(vcpu))
return 0;
Since vcpu->arch.pv.handle is strictly populated after a successful uv_call(),
doesn't it evaluate to 0 during a failure?
Does this mean kvm_s390_pv_destroy_cpu() will return immediately without
freeing the stor_base and sidad pages, allowing a local user to repeatedly
fail protected vCPU creation and exhaust kernel memory?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=3
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
2026-08-03 12:40 ` [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
2026-08-03 13:19 ` sashiko-bot
@ 2026-08-03 14:30 ` Janosch Frank
2026-08-03 14:54 ` Claudio Imbrenda
1 sibling, 1 reply; 34+ messages in thread
From: Janosch Frank @ 2026-08-03 14:30 UTC (permalink / raw)
To: Claudio Imbrenda, linux-kernel
Cc: kvm, linux-s390, borntraeger, david, seiden, nrb, schlameuss, gra
On 8/3/26 14:40, Claudio Imbrenda wrote:
> 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.
Secure guests without cmma in the unsecure guest?
>
> 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 1b3290a5ad1a..9be27db0a21e 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3678,7 +3678,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;
> }
>
This is fenced for destroy cpu, but not for the transition into secure
mode. Can we check "use_cmma" instead of cbrlo and then remove the
fencing in the cpu destroy path?
If cmma is not set-up in vcpu_create, then we exit vcpu creation.
Maybe sprinkle in a warn on for !cbrlo
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
2026-08-03 14:30 ` Janosch Frank
@ 2026-08-03 14:54 ` Claudio Imbrenda
0 siblings, 0 replies; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 14:54 UTC (permalink / raw)
To: Janosch Frank
Cc: linux-kernel, kvm, linux-s390, borntraeger, david, seiden, nrb,
schlameuss, gra
On Mon, 3 Aug 2026 16:30:21 +0200
Janosch Frank <frankja@linux.ibm.com> wrote:
> On 8/3/26 14:40, Claudio Imbrenda wrote:
> > 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.
>
> Secure guests without cmma in the unsecure guest?
normal guests when the vCPU gets destroyed before it's fully
initialized (i.e. something went wrong when creating the vCPU)
>
> >
> > 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 1b3290a5ad1a..9be27db0a21e 100644
> > --- a/arch/s390/kvm/kvm-s390.c
> > +++ b/arch/s390/kvm/kvm-s390.c
> > @@ -3678,7 +3678,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;
> > }
> >
>
> This is fenced for destroy cpu, but not for the transition into secure
> mode. Can we check "use_cmma" instead of cbrlo and then remove the
> fencing in the cpu destroy path?
>
> If cmma is not set-up in vcpu_create, then we exit vcpu creation.
> Maybe sprinkle in a warn on for !cbrlo
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 04/13] KVM: s390: Fix overclearing ESCA in case of error
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (2 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 03/13] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:05 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
` (8 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 vcpu->arch.initialized is still zero.
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 9be27db0a21e..5b2727d7dfd1 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3462,7 +3462,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] 34+ messages in thread* Re: [PATCH v8 04/13] KVM: s390: Fix overclearing ESCA in case of error
2026-08-03 12:40 ` [PATCH v8 04/13] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
@ 2026-08-03 13:05 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 13:05 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: linux-s390, Alexander Gordeev, Heiko Carstens, kvm, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] For KVM_VM_S390_UCONTROL VMs, userspace can trigger an out-of-bounds read and write in `sca_clear_ext_call` and `sca_inject_ext_call` by creating a vCPU with an ID >= 248.
- [High] Memory leak of `vcpu->arch.mc` and its topped-up pages when `kvm_arch_vcpu_create()` fails.
--
--- Patch [4]: [PATCH v8 04/13] KVM: s390: Fix overclearing ESCA in case of error ---
commit 554d58551a2c2c8a2475d02299b28fea5b490098
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix overclearing ESCA in case of error
This commit fixes an issue where destroying a duplicated vCPU clears the ESCA
entry of the original vCPU. It skips clearing the ESCA entry if the vCPU
creation was unsuccessful.
> 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;
[Severity: Critical]
This is a pre-existing issue, but can this out-of-bounds access occur for
ucontrol VMs?
For KVM_VM_S390_UCONTROL VMs, kvm_arch_vcpu_precreate() skips the
sca_can_add_vcpu() check. This allows a user with CAP_SYS_ADMIN to create
vCPUs with IDs up to 254.
However, the sca->cpu array in struct esca_block only has
KVM_S390_ESCA_CPU_SLOTS (248) elements. Because sca_clear_ext_call() is
called unconditionally when destroying the vCPU, it indexes sca->cpu with this
unvalidated vcpu_id before the initialization check.
Would this result in an out-of-bounds read and write to adjacent kernel
memory here, and similarly in sca_inject_ext_call()?
> - if (!kvm_s390_use_sca_entries())
> + if (!kvm_s390_use_sca_entries() || !vcpu->arch.initialized)
> return;
> kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND);
>
[ ... ]
[Severity: High]
This is a pre-existing issue, but does kvm_arch_vcpu_create() leak the MMU
cache on error paths?
If kvm_s390_new_mmu_cache() succeeds, but a later step fails (such as
gmap_new_child() for a ucontrol VM, or ultravisor PV setup failing), the error
path jumps to out_free_sie_block:
out_free_sie_block:
free_page((unsigned long)(vcpu->arch.sie_block));
return rc;
It appears kvm_s390_free_mmu_cache(vcpu->arch.mc) is never called here. Since
the caller kvm_vm_ioctl_create_vcpu() handles the error by freeing the base
vCPU struct without calling kvm_arch_vcpu_destroy(), does this permanently
leak vcpu->arch.mc and its internally topped-up pages?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=4
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call()
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (3 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 04/13] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:21 ` sashiko-bot
2026-08-03 14:50 ` Janosch Frank
2026-08-03 12:40 ` [PATCH v8 06/13] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
` (7 subsequent siblings)
12 siblings, 2 replies; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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. Add extra checks in
sca_ext_call_pending() and sca_inject_ext_call() to make sure UCONTROL
VMs won't touch ESCA.
Fencing does not cause regressions with userspace, since UCONTROL VMs
never used KVM_S390_INTERRUPT ioctls.
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 | 5 +++++
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 2acdff130fa6..6b3f97a7513b 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_is_ucontrol(vcpu->kvm))
+ return 0;
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_is_ucontrol(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 5b2727d7dfd1..21574f57be72 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;
@@ -5456,6 +5459,8 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
struct kvm_s390_interrupt s390int;
struct kvm_s390_irq s390irq = {};
+ if (kvm_is_ucontrol(vcpu->kvm))
+ return -EINVAL;
if (copy_from_user(&s390int, argp, sizeof(s390int)))
return -EFAULT;
if (s390int_to_s390irq(&s390int, &s390irq))
--
2.55.0
^ permalink raw reply related [flat|nested] 34+ messages in thread* Re: [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call()
2026-08-03 12:40 ` [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
@ 2026-08-03 13:21 ` sashiko-bot
2026-08-03 14:50 ` Janosch Frank
1 sibling, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 13:21 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Alexander Gordeev, Heiko Carstens, kvm, linux-s390, Vasily Gorbik
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Hardware-dependent ABI inconsistency for UCONTROL VMs when injecting KVM_S390_INT_EXTERNAL_CALL via KVM_S390_IRQ.
--
--- Patch [5]: [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call() ---
commit 450e8d67402bbac296dca888444bff5561662e98
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: ucontrol: Fix sca_clear_ext_call()
This commit fixes an out-of-bounds access in sca_clear_ext_call() for
UCONTROL VMs by explicitly not touching ESCA. It also fences the
KVM_S390_INTERRUPT ioctl for UCONTROL VMs and adds extra checks to make
sure UCONTROL VMs won't touch ESCA.
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index 2acdff130fa6c..6b3f97a7513b3 100644
> --- a/arch/s390/kvm/interrupt.c
> +++ b/arch/s390/kvm/interrupt.c
[ ... ]
> @@ -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_is_ucontrol(vcpu->kvm))
> + return -EINVAL;
[Severity: Medium]
Will this create a hardware-dependent ABI for UCONTROL VMs when injecting
KVM_S390_INT_EXTERNAL_CALL via KVM_S390_IRQ?
Looking at __inject_extcall(), sca_inject_ext_call() is only executed if the
host supports ESCA:
arch/s390/kvm/interrupt.c:__inject_extcall() {
...
if (kvm_s390_use_sca_entries() && !kvm_s390_pv_cpu_get_handle(vcpu))
return sca_inject_ext_call(vcpu, src_id);
if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
...
}
If the host lacks ESCA support, the UCONTROL check here in
sca_inject_ext_call() is bypassed, and the external call is successfully
queued.
Unlike KVM_S390_INTERRUPT, the KVM_S390_IRQ ioctl is not fenced for UCONTROL
VMs, allowing userspace to trigger this inconsistent behavior. Could this
cause the same ioctl to fail on modern hosts but succeed on older ones?
Would it be better to place the UCONTROL check higher up in __inject_extcall()
to ensure consistent behavior, or to also fence KVM_S390_IRQ for UCONTROL VMs?
>
> + sigp_ctrl = &sca->cpu[vcpu->vcpu_id].sigp_ctrl;
> old_val = READ_ONCE(*sigp_ctrl);
> old_val.c = 0;
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=5
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call()
2026-08-03 12:40 ` [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
2026-08-03 13:21 ` sashiko-bot
@ 2026-08-03 14:50 ` Janosch Frank
2026-08-03 15:03 ` Claudio Imbrenda
1 sibling, 1 reply; 34+ messages in thread
From: Janosch Frank @ 2026-08-03 14:50 UTC (permalink / raw)
To: Claudio Imbrenda, linux-kernel
Cc: kvm, linux-s390, borntraeger, david, seiden, nrb, schlameuss, gra
On 8/3/26 14:40, Claudio Imbrenda wrote:
> 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. Add extra checks in
> sca_ext_call_pending() and sca_inject_ext_call() to make sure UCONTROL
> VMs won't touch ESCA.
>
> Fencing does not cause regressions with userspace, since UCONTROL VMs
> never used KVM_S390_INTERRUPT ioctls.
>
> 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 | 5 +++++
> 2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
> index 2acdff130fa6..6b3f97a7513b 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_is_ucontrol(vcpu->kvm))
> + return 0;
>
> 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_is_ucontrol(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;
Not sure why you only add this here and not at the other two occurences.
But I don't think we need these comments at all.
Dereferencing things before a check is not a great idea in most cases.
Especially if the check validates if the memory has been set up at all :)
> 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 5b2727d7dfd1..21574f57be72 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;
> @@ -5456,6 +5459,8 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
> struct kvm_s390_interrupt s390int;
> struct kvm_s390_irq s390irq = {};
>
> + if (kvm_is_ucontrol(vcpu->kvm))
> + return -EINVAL;
> if (copy_from_user(&s390int, argp, sizeof(s390int)))
> return -EFAULT;
> if (s390int_to_s390irq(&s390int, &s390irq))
Do we need changes to the api documentation for this rc?
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call()
2026-08-03 14:50 ` Janosch Frank
@ 2026-08-03 15:03 ` Claudio Imbrenda
0 siblings, 0 replies; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 15:03 UTC (permalink / raw)
To: Janosch Frank
Cc: linux-kernel, kvm, linux-s390, borntraeger, david, seiden, nrb,
schlameuss, gra
On Mon, 3 Aug 2026 16:50:30 +0200
Janosch Frank <frankja@linux.ibm.com> wrote:
> On 8/3/26 14:40, Claudio Imbrenda wrote:
> > 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. Add extra checks in
> > sca_ext_call_pending() and sca_inject_ext_call() to make sure UCONTROL
> > VMs won't touch ESCA.
> >
> > Fencing does not cause regressions with userspace, since UCONTROL VMs
> > never used KVM_S390_INTERRUPT ioctls.
> >
> > Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> > Fixes: 7d43bafcff17 ("KVM: s390: Make provisions for ESCA utilization")
[...]
> > @@ -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;
>
> Not sure why you only add this here and not at the other two occurences.
because the other two were added later and I forgot about the comment :)
> But I don't think we need these comments at all.
>
> Dereferencing things before a check is not a great idea in most cases.
> Especially if the check validates if the memory has been set up at all :)
>
> > 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 5b2727d7dfd1..21574f57be72 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;
> > @@ -5456,6 +5459,8 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl,
> > struct kvm_s390_interrupt s390int;
> > struct kvm_s390_irq s390irq = {};
> >
> > + if (kvm_is_ucontrol(vcpu->kvm))
> > + return -EINVAL;
> > if (copy_from_user(&s390int, argp, sizeof(s390int)))
> > return -EFAULT;
> > if (s390int_to_s390irq(&s390int, &s390irq))
>
> Do we need changes to the api documentation for this rc?
The existing documentation is already not describing which error codes
are possible and when.
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 06/13] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (4 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 05/13] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:01 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 07/13] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
` (6 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 21574f57be72..e162efaa35b8 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] 34+ messages in thread* Re: [PATCH v8 06/13] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
2026-08-03 12:40 ` [PATCH v8 06/13] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
@ 2026-08-03 13:01 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 13:01 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: Vasily Gorbik, linux-s390, Heiko Carstens, kvm, Alexander Gordeev
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Concurrent large page split causes `large_crste_to_phys()` to dereference an invalid address (`-1`), leading to a host kernel panic via addressing exception.
--
--- Patch [6]: [PATCH v8 06/13] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace ---
commit 7bad2118b8960be854e59fc638949bdda1bbace0
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
This commit fixes several key and CMMA operations to return -EFAULT instead
of PGM_ADDRESSING when acting outside of a memslot.
> diff --git a/arch/s390/kvm/dat.c b/arch/s390/kvm/dat.c
> index ed4259d176295..171b619599089 100644
> --- a/arch/s390/kvm/dat.c
> +++ b/arch/s390/kvm/dat.c
> @@ -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;
[Severity: Critical]
This is a pre-existing issue, but I noticed a potential race condition with
the large page handling here.
Because kvm->mmu_lock is only held for reading during this operation, could
another vCPU concurrently split the large page under the read lock (via
dat_split_crste()), clearing the fc bit?
If dat_entry_walk() succeeds, but the page is split before the implicit read
of *crstep in large_crste_to_phys(), large_crste_to_phys() could observe the
cleared fc bit and return -1.
Passing -1 to the assembly block inside page_reset_referenced() could
trigger an unhandled addressing exception and panic the host kernel since it
lacks exception tables.
Would it be safer to use the already validated snapshot (crste) instead of
dereferencing *crstep again?
skey->skey = page_reset_referenced(large_crste_to_phys(crste, gfn)) << 1;
This same pattern of passing *crstep directly to large_crste_to_phys()
appears to also exist in dat_set_storage_key() and
dat_cond_set_storage_key().
> + return 0;
> }
> old = pgste_get_lock(ptep);
> pgste = old;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=6
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 07/13] KVM: s390: Fix race in __do_essa()
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (5 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 06/13] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 12:56 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 08/13] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
` (5 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 e162efaa35b8..e5c5e9f61cb2 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] 34+ messages in thread* [PATCH v8 08/13] KVM: s390: cmma: Fix dirty tracking when removing memslot
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (6 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 07/13] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:08 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 09/13] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
` (4 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 e5c5e9f61cb2..ba811f0673d1 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -5812,14 +5812,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;
@@ -5830,6 +5846,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);
@@ -5851,7 +5873,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] 34+ messages in thread* Re: [PATCH v8 08/13] KVM: s390: cmma: Fix dirty tracking when removing memslot
2026-08-03 12:40 ` [PATCH v8 08/13] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
@ 2026-08-03 13:08 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 13:08 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: kvm, Vasily Gorbik, Alexander Gordeev, linux-s390, Heiko Carstens
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The CMMA dirty pages counter leaks when unmapped pages (holes) with `cmma_d == 1` are deleted.
--
--- Patch [8]: [PATCH v8 08/13] KVM: s390: cmma: Fix dirty tracking when removing memslot ---
commit 914169226ab516b51f60cbd45659598a2b39525d
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>
KVM: s390: cmma: Fix dirty tracking when removing memslot
This commit decrements the cmma-dirty counter when a memslot is removed
to ensure accurate dirty tracking during migration mode. It also
opportunistically adopts scope-based resource management for the
kvm_s390_mmu_cache.
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index e5c5e9f61cb24..ba811f0673d10 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
[ ... ]
> @@ -5830,6 +5846,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);
> + }
> +
[Severity: High]
Does this code leak the cmma_dirty_pages counter when unmapped pages (holes)
have cmma_d == 1?
Because this pre-walk uses DAT_WALK_IGN_HOLES without DAT_WALK_ANY,
dat_pte_walk_range() will skip calling cmma_d_count_pte() for holes:
arch/s390/kvm/dat.c:dat_pte_walk_range() {
if (pte_hole(READ_ONCE(table->ptes[idx]))) {
if (!(w->flags & DAT_WALK_IGN_HOLES))
return -EFAULT;
if (!(w->flags & DAT_WALK_ANY))
continue;
}
...
}
If a guest page was dirtied (setting cmma_d = 1 and incrementing the
counter), and then the host unmaps the page (e.g., via page reclaim
or MADV_DONTNEED), the PTE becomes a hole but the PGSTE retains
cmma_d == 1.
When the memslot is removed, this pre-walk skips the hole, failing
to decrement cmma_dirty_pages. Then dat_delete_slot() walks the range
with DAT_WALK_ANY and clears cmma_d, causing the counter to permanently
leak.
If this counter never reaches 0, could it stall live migration by causing
userspace to infinite loop waiting for remaining dirty pages to drop to 0?
> switch (change) {
> case KVM_MR_DELETE:
> rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=8
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 09/13] KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (7 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 08/13] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 12:59 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 10/13] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
` (3 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 ba811f0673d1..2741ca323ede 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3875,7 +3875,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] 34+ messages in thread* Re: [PATCH v8 09/13] KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
2026-08-03 12:40 ` [PATCH v8 09/13] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
@ 2026-08-03 12:59 ` sashiko-bot
0 siblings, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 12:59 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 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The dynamically allocated MMU cache (`vcpu->arch.mc`) and its associated cached pages are permanently leaked in the error paths of `kvm_arch_vcpu_create()`.
--
--- Patch [9]: [PATCH v8 09/13] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() ---
commit 468ac730893edf1b533b2a8b139847cb8a9ef03c
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 ba811f0673d10..2741ca323edea 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -3875,7 +3875,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 leak the dynamically
allocated MMU cache (vcpu->arch.mc) and its internal cached pages?
Earlier in kvm_arch_vcpu_create(), the cache is allocated:
vcpu->arch.mc = kvm_s390_new_mmu_cache();
if (!vcpu->arch.mc)
return -ENOMEM;
If the function encounters an error and jumps to out_free_sie_block, it cleans
up the sie_page but returns without calling kvm_s390_free_mmu_cache().
The core KVM code in kvm_vm_ioctl_create_vcpu() skips calling
kvm_arch_vcpu_destroy() when the architecture-specific create function fails,
which might permanently leak the mc memory. This could allow unprivileged
users to trigger a denial of service (OOM) through memory exhaustion by
creating PV vCPUs in a misconfigured environment or exhausting limits.
This leak remains unfixed at the end of the patch series.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260803124040.126471-1-imbrenda@linux.ibm.com?part=9
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v8 10/13] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (8 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 09/13] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 12:51 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 11/13] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
` (2 subsequent siblings)
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 2741ca323ede..9b8a35e7dc82 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3800,21 +3800,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);
@@ -3856,10 +3856,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",
@@ -3867,22 +3866,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] 34+ messages in thread* [PATCH v8 11/13] KVM: s390: Return -EINTR if a signal is pending while faulting-in
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (9 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 10/13] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:19 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 12/13] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
2026-08-03 12:40 ` [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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] 34+ messages in thread* [PATCH v8 12/13] KVM: s390: Fix ordering when adding to SCA
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (10 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 11/13] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:03 ` sashiko-bot
2026-08-03 12:40 ` [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
12 siblings, 1 reply; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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 9b8a35e7dc82..518a69c55e85 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3485,8 +3485,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] 34+ messages in thread* [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
2026-08-03 12:40 [PATCH v8 00/13] KVM: s390: Misc fixes Claudio Imbrenda
` (11 preceding siblings ...)
2026-08-03 12:40 ` [PATCH v8 12/13] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
@ 2026-08-03 12:40 ` Claudio Imbrenda
2026-08-03 13:05 ` sashiko-bot
2026-08-03 15:06 ` Janosch Frank
12 siblings, 2 replies; 34+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 12:40 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] 34+ messages in thread* Re: [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
2026-08-03 12:40 ` [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
@ 2026-08-03 13:05 ` sashiko-bot
2026-08-03 15:06 ` Janosch Frank
1 sibling, 0 replies; 34+ messages in thread
From: sashiko-bot @ 2026-08-03 13:05 UTC (permalink / raw)
To: Claudio Imbrenda
Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev
> 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/20260803124040.126471-1-imbrenda@linux.ibm.com?part=13
^ permalink raw reply [flat|nested] 34+ messages in thread* Re: [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
2026-08-03 12:40 ` [PATCH v8 13/13] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
2026-08-03 13:05 ` sashiko-bot
@ 2026-08-03 15:06 ` Janosch Frank
1 sibling, 0 replies; 34+ messages in thread
From: Janosch Frank @ 2026-08-03 15:06 UTC (permalink / raw)
To: Claudio Imbrenda, linux-kernel
Cc: kvm, linux-s390, borntraeger, david, seiden, nrb, schlameuss, gra
On 8/3/26 14:40, Claudio Imbrenda wrote:
> 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.
There are times when the creation fails and we still get a handle to
destroy the cpu again. But you're describing the case where the destroy
bit and handle are not set so that's fine.
>
> 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>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
^ permalink raw reply [flat|nested] 34+ messages in thread