Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes
@ 2026-08-03 16:09 Claudio Imbrenda
  2026-08-03 16:09 ` [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails Claudio Imbrenda
                   ` (23 more replies)
  0 siblings, 24 replies; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

Ciao Paolo,

In this pull request there are a bunch of fixes to various KVM/s390 and
vfio-ccw issues.

There are still some small known bugs, which will be addressed later in
a different series.

The following changes since commit 9972befc3e34ff8b6847198c84f11bfc312dde40:

  KVM: s390: Fall back to short-term pinning in MAP ioctl (2026-07-27 09:23:53 +0200)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git tags/kvm-s390-master-7.2-3

for you to fetch changes up to feadc5e84dcb53422a437556c35af9efd9826fd5:

  KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() (2026-08-03 17:09:46 +0200)

----------------------------------------------------------------
KVM: s390: Misc fixes for 7.2

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.

----------------------------------------------------------------
Claudio Imbrenda (13):
      KVM: s390: Fix unlikely NULL gmap dereference
      KVM: s390: Do not free SCA if it was not allocated
      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()

Eric Farman (10):
      s390/vfio_ccw: Free all memory if cp_init() fails
      s390/vfio_ccw: Limit the number of channel program segments
      s390/vfio_ccw: Fix out of bounds check on CCW array
      s390/vfio_ccw: Ensure first IDAW remains constant
      s390/vfio_ccw: Calculate idal length based on idaw type
      s390/vfio_ccw: Ensure index for read/write regions are within range
      s390/vfio_ccw: Cancel existing workqueues
      s390/vfio_ccw: Move cp cleanup out of not operational
      s390/vfio_ccw: Selectively expand io_mutex
      s390/vfio_ccw: Implement a crw lock

 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            | 125 +++++++++++++++++++++++-------------
 arch/s390/kvm/priv.c                |  10 +--
 arch/s390/kvm/pv.c                  |  43 +++++++------
 drivers/s390/cio/vfio_ccw_async.c   |  16 +++++
 drivers/s390/cio/vfio_ccw_chp.c     |  31 +++++++--
 drivers/s390/cio/vfio_ccw_cp.c      |  74 +++++++++++++++------
 drivers/s390/cio/vfio_ccw_cp.h      |  10 +++
 drivers/s390/cio/vfio_ccw_drv.c     |  21 +++++-
 drivers/s390/cio/vfio_ccw_fsm.c     |   8 ++-
 drivers/s390/cio/vfio_ccw_ops.c     |  39 +++++++++--
 drivers/s390/cio/vfio_ccw_private.h |  10 ++-
 16 files changed, 320 insertions(+), 118 deletions(-)

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:28   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments Claudio Imbrenda
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The routine cp_free() is called to unpin/free any memory once an I/O
is completed successfully, or if cp_prefetch() fails. But if cp_init()
fails, and cp->initialized is not enabled, the same routine cannot be
used to free all the memory.

An attempt to address this exists in ccwchain_handle_ccw(), where a
single call to ccwchain_free() is made for the currently-processed
CCW segment. But this will leak other segments (created as a result
of a Transfer in Channel) that had been allocated as part of the same
channel program.

Address this by performing the cleanup outside of the recursive
ccwchain_handle_ccw()/ccwchain_loop_tic() logic.

Fixes: 8b515be512a2 ("vfio-ccw: Fix memory leak and don't call cp_free in cp_init")
Cc: stable@vger.kernel.org
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_cp.c | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 7561aa7d3e01..086d1b54bdb0 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -455,9 +455,6 @@ static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
 	/* Loop for tics on this new chain. */
 	ret = ccwchain_loop_tic(chain, cp);
 
-	if (ret)
-		ccwchain_free(chain);
-
 	return ret;
 }
 
@@ -486,6 +483,23 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp)
 	return 0;
 }
 
+static int ccwchain_build_ccws(dma32_t cda, struct channel_program *cp)
+{
+	struct ccwchain *chain, *temp;
+	int ret;
+
+	ret = ccwchain_handle_ccw(cda, cp);
+
+	if (ret) {
+		/* Cleanup if an error occurred */
+		list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
+			ccwchain_free(chain);
+		}
+	}
+
+	return ret;
+}
+
 static int ccwchain_fetch_tic(struct ccw1 *ccw,
 			      struct channel_program *cp)
 {
@@ -735,7 +749,7 @@ int cp_init(struct channel_program *cp, union orb *orb)
 	memcpy(&cp->orb, orb, sizeof(*orb));
 
 	/* Build a ccwchain for the first CCW segment */
-	ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
+	ret = ccwchain_build_ccws(orb->cmd.cpa, cp);
 
 	if (!ret)
 		cp->initialized = true;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
  2026-08-03 16:09 ` [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:32   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 03/23] s390/vfio_ccw: Fix out of bounds check on CCW array Claudio Imbrenda
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The processing of channel programs, and the CCWs within them, is done
recursively. As such, there is an arbitrary (but not architectural)
limit to the number of CCWs that can exist in a single channel program.

The vfio-ccw logic breaks these channel programs into segments whenever
it encounters a Transfer-In-Channel (TIC) CCW, and the combined number
of segments count towards the global limit. Impose an equivalent limit
to the number of segments until such logic can be made non-recursive.

Fixes: 0a19e61e6d4c ("vfio: ccw: introduce channel program interfaces")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_cp.c | 6 ++++++
 drivers/s390/cio/vfio_ccw_cp.h | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 086d1b54bdb0..1c2890d139c6 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -332,6 +332,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len)
 		goto out_err;
 
 	list_add_tail(&chain->next, &cp->ccwchain_list);
+	cp->ccwchain_count++;
 
 	return chain;
 
@@ -441,6 +442,10 @@ static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
 	if (len < 0)
 		return len;
 
+	/* Limit number of chains in a single channel program */
+	if (cp->ccwchain_count >= CCWCHAIN_COUNT_MAX)
+		return -EINVAL;
+
 	/* Need alloc a new chain for this one. */
 	chain = ccwchain_alloc(cp, len);
 	if (!chain)
@@ -745,6 +750,7 @@ int cp_init(struct channel_program *cp, union orb *orb)
 			vdev->dev,
 			"Prefetching channel program even though prefetch not specified in ORB");
 
+	cp->ccwchain_count = 0;
 	INIT_LIST_HEAD(&cp->ccwchain_list);
 	memcpy(&cp->orb, orb, sizeof(*orb));
 
diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h
index fc31eb699807..a9b1d8dbc6f6 100644
--- a/drivers/s390/cio/vfio_ccw_cp.h
+++ b/drivers/s390/cio/vfio_ccw_cp.h
@@ -23,11 +23,18 @@
  */
 #define CCWCHAIN_LEN_MAX	256
 
+/*
+ * Maximum number of chains
+ */
+#define CCWCHAIN_COUNT_MAX	16
+
 /**
  * struct channel_program - manage information for channel program
  * @ccwchain_list: list head of ccwchains
  * @orb: orb for the currently processed ssch request
  * @initialized: whether this instance is actually initialized
+ * @guest_cp: copy of guest channel program
+ * @ccwchain_count: number of channel program segments (linked by TIC)
  *
  * @ccwchain_list is the head of a ccwchain list, that contents the
  * translated result of the guest channel program that pointed out by
@@ -38,6 +45,7 @@ struct channel_program {
 	union orb orb;
 	bool initialized;
 	struct ccw1 *guest_cp;
+	unsigned int ccwchain_count;
 };
 
 int cp_init(struct channel_program *cp, union orb *orb);
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 03/23] s390/vfio_ccw: Fix out of bounds check on CCW array
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
  2026-08-03 16:09 ` [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails Claudio Imbrenda
  2026-08-03 16:09 ` [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:09 ` [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant Claudio Imbrenda
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The routine ccwchain_calc_length() counts the number of channel
command words (CCWs) that are chained together in a single channel
program, and rejects anything larger than CCWCHAIN_LEN_MAX (256) CCWs.

The loop itself is "do..while (count < 257)", and while the logic in
is_cpa_within_range() correctly adjusts between the 0-index array of
CCWs and the count of CCWs starting at 1, this means it would look
at a possible 257th CCW before ending the loop and (correctly)
returning an error.

Fix this by restructuring the loop to break as soon as 256 CCWs
(thus indexes 0-255) are examined, without looking at memory
outside the range.

Fixes: 0a19e61e6d4c ("vfio: ccw: introduce channel program interfaces")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_cp.c | 17 +++++------------
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 1c2890d139c6..af632f9d5453 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -377,11 +377,9 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
 static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
 {
 	struct ccw1 *ccw = cp->guest_cp;
-	int cnt = 0;
-
-	do {
-		cnt++;
+	int cnt;
 
+	for (cnt = 1; cnt <= CCWCHAIN_LEN_MAX; cnt++, ccw++) {
 		/*
 		 * We want to keep counting if the current CCW has the
 		 * command-chaining flag enabled, or if it is a TIC CCW
@@ -391,15 +389,10 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
 		 * after the TIC, depending on the results of its operation.
 		 */
 		if (!ccw_is_chain(ccw) && !is_tic_within_range(ccw, iova, cnt))
-			break;
-
-		ccw++;
-	} while (cnt < CCWCHAIN_LEN_MAX + 1);
-
-	if (cnt == CCWCHAIN_LEN_MAX + 1)
-		cnt = -EINVAL;
+			return cnt;
+	}
 
-	return cnt;
+	return -EINVAL;
 }
 
 static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp)
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (2 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 03/23] s390/vfio_ccw: Fix out of bounds check on CCW array Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:24   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type Claudio Imbrenda
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The first IDAW in a list does not need to be on a 2K/4K boundary
like all others, and so is read separately to accurately calculate
the size of the buffer needed to read the full IDAL.

Verify that the address found in the first IDAW is unchanged between
reads, to ensure a consistent set of IDAWs being worked with.

Fixes: 01aa26c672c0 ("s390/cio: Combine direct and indirect CCW paths")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_cp.c | 16 ++++++++++++++++
 drivers/s390/cio/vfio_ccw_cp.h |  2 ++
 2 files changed, 18 insertions(+)

diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index af632f9d5453..6275794751cb 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -523,6 +523,7 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
 		&container_of(cp, struct vfio_ccw_private, cp)->vdev;
 	dma64_t *idaws;
 	dma32_t *idaws_f1;
+	u64 first_idaw;
 	int idal_len = idaw_nr * sizeof(*idaws);
 	int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
 	int idaw_mask = ~(idaw_size - 1);
@@ -539,6 +540,18 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
 			kfree(idaws);
 			return ERR_PTR(ret);
 		}
+
+		idaws_f1 = (dma32_t *)idaws;
+		if (cp->orb.cmd.c64)
+			first_idaw = dma64_to_u64(idaws[0]);
+		else
+			first_idaw = dma32_to_u32(idaws_f1[0]);
+
+		/* Unexpected mismatch from earlier read */
+		if (first_idaw != cp->guest_iova) {
+			kfree(idaws);
+			return ERR_PTR(-EINVAL);
+		}
 	} else {
 		/* Fabricate an IDAL based off CCW data address */
 		if (cp->orb.cmd.c64) {
@@ -604,6 +617,9 @@ static int ccw_count_idaws(struct ccw1 *ccw,
 		iova = dma32_to_u32(ccw->cda);
 	}
 
+	/* Save the read address for later */
+	cp->guest_iova = iova;
+
 	/* Format-1 IDAWs operate on 2K each */
 	if (!cp->orb.cmd.c64)
 		return idal_2k_nr_words((void *)iova, bytes);
diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h
index a9b1d8dbc6f6..9af98ff12d67 100644
--- a/drivers/s390/cio/vfio_ccw_cp.h
+++ b/drivers/s390/cio/vfio_ccw_cp.h
@@ -35,6 +35,7 @@
  * @initialized: whether this instance is actually initialized
  * @guest_cp: copy of guest channel program
  * @ccwchain_count: number of channel program segments (linked by TIC)
+ * @guest_iova: first data address of a guest channel program
  *
  * @ccwchain_list is the head of a ccwchain list, that contents the
  * translated result of the guest channel program that pointed out by
@@ -46,6 +47,7 @@ struct channel_program {
 	bool initialized;
 	struct ccw1 *guest_cp;
 	unsigned int ccwchain_count;
+	u64 guest_iova;
 };
 
 int cp_init(struct channel_program *cp, union orb *orb);
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (3 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:24   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range Claudio Imbrenda
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

Sashiko pointed out that get_guest_idal() unconditionally calculates
the length of the IDAL presuming everything is a Format-2 IDAW.

The output of vfio-ccw is always Format-2, but the input can be either
Format-1 (31-bit addresses) or Format-2 (64-bit addresses). As a result,
the size of the guest IDAL may be incorrect and should be trimmed down.

Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Link: https://lore.kernel.org/r/20260720203400.7328E1F000E9@smtp.kernel.org/
Fixes: 1b676fe3d9d3 ("vfio/ccw: handle a guest Format-1 IDAL")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_cp.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 6275794751cb..5ef082b8289a 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -233,6 +233,7 @@ static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
 }
 
 #define idal_is_2k(_cp) (!(_cp)->orb.cmd.c64 || (_cp)->orb.cmd.i2k)
+#define get_idaw_size(_cp) ((_cp)->orb.cmd.c64 ? sizeof(u64) : sizeof(u32))
 
 /*
  * Helpers to operate ccwchain.
@@ -524,7 +525,7 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
 	dma64_t *idaws;
 	dma32_t *idaws_f1;
 	u64 first_idaw;
-	int idal_len = idaw_nr * sizeof(*idaws);
+	int idal_len = idaw_nr * get_idaw_size(cp);
 	int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
 	int idaw_mask = ~(idaw_size - 1);
 	int i, ret;
@@ -593,7 +594,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
 	struct vfio_device *vdev =
 		&container_of(cp, struct vfio_ccw_private, cp)->vdev;
 	u64 iova;
-	int size = cp->orb.cmd.c64 ? sizeof(u64) : sizeof(u32);
+	int size = get_idaw_size(cp);
 	int ret;
 	int bytes = 1;
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (4 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:34   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues Claudio Imbrenda
                   ` (17 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The introduction of the capability chain rightly clamped the
region indexes to the range of the capabilities itself, but
neglected to do so for the existing read/write regions which
should also be enforced.

Fixes: db8e5d17ac03 ("vfio-ccw: add capabilities chain")
Cc: stable@vger.kernel.org
Cc: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_async.c | 16 ++++++++++++++++
 drivers/s390/cio/vfio_ccw_chp.c   | 15 +++++++++++++++
 drivers/s390/cio/vfio_ccw_ops.c   |  7 +++----
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_async.c b/drivers/s390/cio/vfio_ccw_async.c
index 420d89ba7f83..4aff0b58fa5d 100644
--- a/drivers/s390/cio/vfio_ccw_async.c
+++ b/drivers/s390/cio/vfio_ccw_async.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/vfio.h>
+#include <linux/nospec.h>
 
 #include "vfio_ccw_private.h"
 
@@ -24,11 +25,20 @@ static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
 		return -EINVAL;
 
 	mutex_lock(&private->io_mutex);
+
+	if (i >= private->num_regions) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	i = array_index_nospec(i, private->num_regions);
 	region = private->region[i].data;
 	if (copy_to_user(buf, (void *)region + pos, count))
 		ret = -EFAULT;
 	else
 		ret = count;
+
+out_unlock:
 	mutex_unlock(&private->io_mutex);
 	return ret;
 }
@@ -48,6 +58,12 @@ static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
 	if (!mutex_trylock(&private->io_mutex))
 		return -EAGAIN;
 
+	if (i >= private->num_regions) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	i = array_index_nospec(i, private->num_regions);
 	region = private->region[i].data;
 	if (copy_from_user((void *)region + pos, buf, count)) {
 		ret = -EFAULT;
diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
index 38c176cf6295..f3015132d4b5 100644
--- a/drivers/s390/cio/vfio_ccw_chp.c
+++ b/drivers/s390/cio/vfio_ccw_chp.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/nospec.h>
 #include <linux/vfio.h>
 #include "vfio_ccw_private.h"
 
@@ -26,6 +27,13 @@ static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private,
 		return -EINVAL;
 
 	mutex_lock(&private->io_mutex);
+
+	if (i >= private->num_regions) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	i = array_index_nospec(i, private->num_regions);
 	region = private->region[i].data;
 
 	if (cio_update_schib(sch)) {
@@ -97,6 +105,12 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
 		list_del(&crw->next);
 
 	mutex_lock(&private->io_mutex);
+	if (i >= private->num_regions) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	i = array_index_nospec(i, private->num_regions);
 	region = private->region[i].data;
 
 	if (crw)
@@ -109,6 +123,7 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
 
 	region->crw = 0;
 
+out:
 	mutex_unlock(&private->io_mutex);
 
 	kfree(crw);
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 45ec722d25ea..032a1cdf4df7 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -243,6 +243,7 @@ static ssize_t vfio_ccw_mdev_read(struct vfio_device *vdev,
 		return vfio_ccw_mdev_read_io_region(private, buf, count, ppos);
 	default:
 		index -= VFIO_CCW_NUM_REGIONS;
+		index = array_index_nospec(index, private->num_regions);
 		return private->region[index].ops->read(private, buf, count,
 							ppos);
 	}
@@ -295,6 +296,7 @@ static ssize_t vfio_ccw_mdev_write(struct vfio_device *vdev,
 		return vfio_ccw_mdev_write_io_region(private, buf, count, ppos);
 	default:
 		index -= VFIO_CCW_NUM_REGIONS;
+		index = array_index_nospec(index, private->num_regions);
 		return private->region[index].ops->write(private, buf, count,
 							 ppos);
 	}
@@ -338,11 +340,8 @@ static int vfio_ccw_mdev_ioctl_get_region_info(struct vfio_device *vdev,
 		    VFIO_CCW_NUM_REGIONS + private->num_regions)
 			return -EINVAL;
 
-		info->index = array_index_nospec(info->index,
-						 VFIO_CCW_NUM_REGIONS +
-						 private->num_regions);
-
 		i = info->index - VFIO_CCW_NUM_REGIONS;
+		i = array_index_nospec(i, private->num_regions);
 
 		info->offset = VFIO_CCW_INDEX_TO_OFFSET(info->index);
 		info->size = private->region[i].size;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (5 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:41   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational Claudio Imbrenda
                   ` (16 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The initialization of the io_work and crw_work workqueues begs the
question of whether they should be un-initialized. Add the corresponding
cleanup tags in _release_dev to ensure work isn't dispatched after
the private struct is free'd.

Suggested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Fixes: e5f84dbaea59 ("vfio: ccw: return I/O results asynchronously")
Fixes: 3f02cb2fd9d2 ("vfio-ccw: Wire up the CRW irq and CRW region")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_ops.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 032a1cdf4df7..d361d1fde3a0 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -131,6 +131,13 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
 		container_of(vdev, struct vfio_ccw_private, vdev);
 	struct vfio_ccw_crw *crw, *temp;
 
+	/*
+	 * Ensure these work items are fully drained, so none can
+	 * fire after being released.
+	 */
+	cancel_work_sync(&private->io_work);
+	cancel_work_sync(&private->crw_work);
+
 	list_for_each_entry_safe(crw, temp, &private->crw, next) {
 		list_del(&crw->next);
 		kfree(crw);
@@ -202,6 +209,14 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)
 		container_of(vdev, struct vfio_ccw_private, vdev);
 
 	vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
+
+	/*
+	 * Ensure these work items are drained, in the event the
+	 * device is re-opened instead of released.
+	 */
+	cancel_work_sync(&private->io_work);
+	cancel_work_sync(&private->crw_work);
+
 	vfio_ccw_unregister_dev_regions(private);
 }
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (6 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:39   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex Claudio Imbrenda
                   ` (15 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The fsm_notoper() routine is called when the device has been
lost, and is (by definition) no longer operational. Since this
can happen asynchronously from the normal behavior of the
driver, the cleanup may happen when holding other locks
in the calling sequence (notably, the cio subchannel lock).

Push the cleanup of the private->cp resources to a workqueue,
where it can be done out from under that lock sequence and
a future patch can safely manage the locking requirements.

Fixes: 204b394a23ad ("vfio/ccw: Move FSM open/close to MDEV open/close")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_drv.c     |  9 +++++++++
 drivers/s390/cio/vfio_ccw_fsm.c     |  3 +--
 drivers/s390/cio/vfio_ccw_ops.c     | 13 +++++++++++++
 drivers/s390/cio/vfio_ccw_private.h |  3 +++
 4 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 1a095085bc72..c197ad5ab580 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -125,6 +125,15 @@ void vfio_ccw_crw_todo(struct work_struct *work)
 		eventfd_signal(private->crw_trigger);
 }
 
+void vfio_ccw_notoper_todo(struct work_struct *work)
+{
+	struct vfio_ccw_private *private;
+
+	private = container_of(work, struct vfio_ccw_private, notoper_work);
+
+	cp_free(&private->cp);
+}
+
 /*
  * Css driver callbacks
  */
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 4d7988ea47ef..4d47a3c7b9a0 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -170,8 +170,7 @@ static void fsm_notoper(struct vfio_ccw_private *private,
 	css_sched_sch_todo(sch, SCH_TODO_UNREG);
 	private->state = VFIO_CCW_STATE_NOT_OPER;
 
-	/* This is usually handled during CLOSE event */
-	cp_free(&private->cp);
+	queue_work(vfio_ccw_work_q, &private->notoper_work);
 }
 
 /*
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index d361d1fde3a0..1df6d649565b 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -54,6 +54,7 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
 	INIT_LIST_HEAD(&private->crw);
 	INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
 	INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
+	INIT_WORK(&private->notoper_work, vfio_ccw_notoper_todo);
 
 	private->cp.guest_cp = kzalloc_objs(struct ccw1, CCWCHAIN_LEN_MAX);
 	if (!private->cp.guest_cp)
@@ -134,9 +135,16 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
 	/*
 	 * Ensure these work items are fully drained, so none can
 	 * fire after being released.
+	 *
+	 * notoper_work should have nothing to do here, because only
+	 * open devices could have channel_program resources in use
+	 * and those would be released during close. Nevertheless,
+	 * call flush here as well to be certain anything that was
+	 * allocated is freed.
 	 */
 	cancel_work_sync(&private->io_work);
 	cancel_work_sync(&private->crw_work);
+	flush_work(&private->notoper_work);
 
 	list_for_each_entry_safe(crw, temp, &private->crw, next) {
 		list_del(&crw->next);
@@ -213,9 +221,14 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)
 	/*
 	 * Ensure these work items are drained, in the event the
 	 * device is re-opened instead of released.
+	 *
+	 * notoper_work needs to be given a chance to run if it
+	 * is queued, so any memory associated with the channel
+	 * program can be returned.
 	 */
 	cancel_work_sync(&private->io_work);
 	cancel_work_sync(&private->crw_work);
+	flush_work(&private->notoper_work);
 
 	vfio_ccw_unregister_dev_regions(private);
 }
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 0501d4bbcdbd..e2256402b089 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -102,6 +102,7 @@ struct vfio_ccw_parent {
  * @req_trigger: eventfd ctx for signaling userspace to return device
  * @io_work: work for deferral process of I/O handling
  * @crw_work: work for deferral process of CRW handling
+ * @notoper_work: work for deferred processing in not-operational state
  */
 struct vfio_ccw_private {
 	struct vfio_device vdev;
@@ -125,11 +126,13 @@ struct vfio_ccw_private {
 	struct eventfd_ctx	*req_trigger;
 	struct work_struct	io_work;
 	struct work_struct	crw_work;
+	struct work_struct	notoper_work;
 } __aligned(8);
 
 int vfio_ccw_sch_quiesce(struct subchannel *sch);
 void vfio_ccw_sch_io_todo(struct work_struct *work);
 void vfio_ccw_crw_todo(struct work_struct *work);
+void vfio_ccw_notoper_todo(struct work_struct *work);
 
 extern struct mdev_driver vfio_ccw_mdev_driver;
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (7 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:54   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock Claudio Imbrenda
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

The io_mutex was defined to serialize the io_regions, but then has
also sort of been associated with the I/O themselves because of
the close relationship they share.

With the handful of races that are possible, the choices are either to:
 A) expand the scope of io_mutex to close these remaining windows, or
 B) reduce the scope of io_mutex to just io_region, and introduce a new
    lock mechanism for the remaining I/O resources

This patch implements A, since B brings with it a lot more interactions
that would need to be tracked and kept in a correct hierarchy. It also
takes advantage of the workqueue element for cp_free() that now gets
called out of fsm_notoper(), which could be invoked out of an interrupt
context and thus cannot acquire a mutex itself.

Fixes: 4f76617378ee ("vfio-ccw: protect the I/O region")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_chp.c     | 2 +-
 drivers/s390/cio/vfio_ccw_cp.c      | 8 +++++++-
 drivers/s390/cio/vfio_ccw_drv.c     | 6 ++++--
 drivers/s390/cio/vfio_ccw_fsm.c     | 5 +++++
 drivers/s390/cio/vfio_ccw_private.h | 3 ++-
 5 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
index f3015132d4b5..9269b54f5cfd 100644
--- a/drivers/s390/cio/vfio_ccw_chp.c
+++ b/drivers/s390/cio/vfio_ccw_chp.c
@@ -98,13 +98,13 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
 	if (pos + count > sizeof(*region))
 		return -EINVAL;
 
+	mutex_lock(&private->io_mutex);
 	crw = list_first_entry_or_null(&private->crw,
 				       struct vfio_ccw_crw, next);
 
 	if (crw)
 		list_del(&crw->next);
 
-	mutex_lock(&private->io_mutex);
 	if (i >= private->num_regions) {
 		ret = -EINVAL;
 		goto out;
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 5ef082b8289a..58722c4baa25 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -977,17 +977,23 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
  */
 bool cp_iova_pinned(struct channel_program *cp, u64 iova, u64 length)
 {
+	struct vfio_ccw_private *private =
+		container_of(cp, struct vfio_ccw_private, cp);
 	struct ccwchain *chain;
 	int i;
 
 	if (!cp->initialized)
 		return false;
 
+	mutex_lock(&private->io_mutex);
 	list_for_each_entry(chain, &cp->ccwchain_list, next) {
 		for (i = 0; i < chain->ch_len; i++)
-			if (page_array_iova_pinned(&chain->ch_pa[i], iova, length))
+			if (page_array_iova_pinned(&chain->ch_pa[i], iova, length)) {
+				mutex_unlock(&private->io_mutex);
 				return true;
+			}
 	}
+	mutex_unlock(&private->io_mutex);
 
 	return false;
 }
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index c197ad5ab580..757ff5b2556e 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -91,6 +91,7 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
 
 	is_final = !(scsw_actl(&irb->scsw) &
 		     (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
+	mutex_lock(&private->io_mutex);
 	if (scsw_is_solicited(&irb->scsw)) {
 		cp_update_scsw(&private->cp, &irb->scsw);
 		if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) {
@@ -98,9 +99,7 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
 			cp_is_finished = true;
 		}
 	}
-	mutex_lock(&private->io_mutex);
 	memcpy(private->io_region->irb_area, irb, sizeof(*irb));
-	mutex_unlock(&private->io_mutex);
 
 	/*
 	 * Reset to IDLE only if processing of a channel program
@@ -110,6 +109,7 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
 	 */
 	if (cp_is_finished)
 		private->state = VFIO_CCW_STATE_IDLE;
+	mutex_unlock(&private->io_mutex);
 
 	if (private->io_trigger)
 		eventfd_signal(private->io_trigger);
@@ -131,7 +131,9 @@ void vfio_ccw_notoper_todo(struct work_struct *work)
 
 	private = container_of(work, struct vfio_ccw_private, notoper_work);
 
+	mutex_lock(&private->io_mutex);
 	cp_free(&private->cp);
+	mutex_unlock(&private->io_mutex);
 }
 
 /*
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 4d47a3c7b9a0..5fd94e9d5c61 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -170,6 +170,7 @@ static void fsm_notoper(struct vfio_ccw_private *private,
 	css_sched_sch_todo(sch, SCH_TODO_UNREG);
 	private->state = VFIO_CCW_STATE_NOT_OPER;
 
+	/* This routine could be called from IRQ context, so defer */
 	queue_work(vfio_ccw_work_q, &private->notoper_work);
 }
 
@@ -409,7 +410,11 @@ static void fsm_close(struct vfio_ccw_private *private,
 
 	private->state = VFIO_CCW_STATE_STANDBY;
 	spin_unlock_irq(&sch->lock);
+
+	mutex_lock(&private->io_mutex);
 	cp_free(&private->cp);
+	mutex_unlock(&private->io_mutex);
+
 	return;
 
 err_unlock:
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index e2256402b089..739121116ab6 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -88,7 +88,8 @@ struct vfio_ccw_parent {
  * @state: internal state of the device
  * @completion: synchronization helper of the I/O completion
  * @io_region: MMIO region to input/output I/O arguments/results
- * @io_mutex: protect against concurrent update of I/O regions
+ * @io_mutex: protect against concurrent update of I/O resources
+ *            and @cp lifecycle
  * @region: additional regions for other subchannel operations
  * @cmd_region: MMIO region for asynchronous I/O commands other than START
  * @schib_region: MMIO region for SCHIB information
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (8 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:51   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 11/23] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
                   ` (13 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

From: Eric Farman <farman@linux.ibm.com>

Unlike the channel_program struct, which covers synchronous I/O
submissions and asynchronous interrupts, the CRW region relies
exclusively on asynchronous events coming from hardware.

Implement a lock to manage the list of those payloads, to ensure
they are read cohesively.

Fixes: 3f02cb2fd9d2 ("vfio-ccw: Wire up the CRW irq and CRW region")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Farhan Ali <alifm@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
---
 drivers/s390/cio/vfio_ccw_chp.c     | 26 ++++++++++++++++----------
 drivers/s390/cio/vfio_ccw_drv.c     |  6 ++++++
 drivers/s390/cio/vfio_ccw_ops.c     |  4 ++++
 drivers/s390/cio/vfio_ccw_private.h |  4 ++++
 4 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
index 9269b54f5cfd..7708eb4d6de0 100644
--- a/drivers/s390/cio/vfio_ccw_chp.c
+++ b/drivers/s390/cio/vfio_ccw_chp.c
@@ -93,18 +93,13 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
 	loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
 	struct ccw_crw_region *region;
 	struct vfio_ccw_crw *crw;
+	unsigned long flags;
 	int ret;
 
 	if (pos + count > sizeof(*region))
 		return -EINVAL;
 
 	mutex_lock(&private->io_mutex);
-	crw = list_first_entry_or_null(&private->crw,
-				       struct vfio_ccw_crw, next);
-
-	if (crw)
-		list_del(&crw->next);
-
 	if (i >= private->num_regions) {
 		ret = -EINVAL;
 		goto out;
@@ -113,6 +108,16 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
 	i = array_index_nospec(i, private->num_regions);
 	region = private->region[i].data;
 
+	spin_lock_irqsave(&private->crw_lock, flags);
+	crw = list_first_entry_or_null(&private->crw,
+				       struct vfio_ccw_crw, next);
+
+	if (crw)
+		list_del(&crw->next);
+
+	/* Drop CRW lock while copying to userspace */
+	spin_unlock_irqrestore(&private->crw_lock, flags);
+
 	if (crw)
 		memcpy(&region->crw, &crw->crw, sizeof(region->crw));
 
@@ -122,15 +127,16 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
 		ret = count;
 
 	region->crw = 0;
-
-out:
-	mutex_unlock(&private->io_mutex);
-
 	kfree(crw);
 
 	/* Notify the guest if more CRWs are on our queue */
+	spin_lock_irqsave(&private->crw_lock, flags);
 	if (!list_empty(&private->crw) && private->crw_trigger)
 		eventfd_signal(private->crw_trigger);
+	spin_unlock_irqrestore(&private->crw_lock, flags);
+
+out:
+	mutex_unlock(&private->io_mutex);
 
 	return ret;
 }
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 757ff5b2556e..ab6b518cc353 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -118,11 +118,14 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
 void vfio_ccw_crw_todo(struct work_struct *work)
 {
 	struct vfio_ccw_private *private;
+	unsigned long flags;
 
 	private = container_of(work, struct vfio_ccw_private, crw_work);
 
+	spin_lock_irqsave(&private->crw_lock, flags);
 	if (!list_empty(&private->crw) && private->crw_trigger)
 		eventfd_signal(private->crw_trigger);
+	spin_unlock_irqrestore(&private->crw_lock, flags);
 }
 
 void vfio_ccw_notoper_todo(struct work_struct *work)
@@ -286,6 +289,7 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
 			       unsigned int rsid)
 {
 	struct vfio_ccw_crw *crw;
+	unsigned long flags;
 
 	/*
 	 * If unable to allocate a CRW, just drop the event and
@@ -303,7 +307,9 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
 	crw->crw.erc = erc;
 	crw->crw.rsid = rsid;
 
+	spin_lock_irqsave(&private->crw_lock, flags);
 	list_add_tail(&crw->next, &private->crw);
+	spin_unlock_irqrestore(&private->crw_lock, flags);
 	queue_work(vfio_ccw_work_q, &private->crw_work);
 }
 
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 1df6d649565b..5ce91285c7d5 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -55,6 +55,7 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
 	INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
 	INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
 	INIT_WORK(&private->notoper_work, vfio_ccw_notoper_todo);
+	spin_lock_init(&private->crw_lock);
 
 	private->cp.guest_cp = kzalloc_objs(struct ccw1, CCWCHAIN_LEN_MAX);
 	if (!private->cp.guest_cp)
@@ -131,6 +132,7 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
 	struct vfio_ccw_private *private =
 		container_of(vdev, struct vfio_ccw_private, vdev);
 	struct vfio_ccw_crw *crw, *temp;
+	unsigned long flags;
 
 	/*
 	 * Ensure these work items are fully drained, so none can
@@ -146,10 +148,12 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
 	cancel_work_sync(&private->crw_work);
 	flush_work(&private->notoper_work);
 
+	spin_lock_irqsave(&private->crw_lock, flags);
 	list_for_each_entry_safe(crw, temp, &private->crw, next) {
 		list_del(&crw->next);
 		kfree(crw);
 	}
+	spin_unlock_irqrestore(&private->crw_lock, flags);
 
 	kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
 	kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 739121116ab6..3bd0171d38d0 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -98,6 +98,8 @@ struct vfio_ccw_parent {
  * @cp: channel program for the current I/O operation
  * @irb: irb info received from interrupt
  * @scsw: scsw info
+ * @crw_lock: serialization of CRW list information
+ * @crw: list of Channel Report Word elements
  * @io_trigger: eventfd ctx for signaling userspace I/O results
  * @crw_trigger: eventfd ctx for signaling userspace CRW information
  * @req_trigger: eventfd ctx for signaling userspace to return device
@@ -120,6 +122,8 @@ struct vfio_ccw_private {
 	struct channel_program	cp;
 	struct irb		irb;
 	union scsw		scsw;
+
+	spinlock_t		crw_lock;
 	struct list_head	crw;
 
 	struct eventfd_ctx	*io_trigger;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [GIT PULL v1 11/23] KVM: s390: Fix unlikely NULL gmap dereference
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (9 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:43   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 12/23] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-2-imbrenda@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 c172f9b212d1..b4182ca4435f 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] 47+ messages in thread

* [GIT PULL v1 12/23] KVM: s390: Do not free SCA if it was not allocated
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (10 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 11/23] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:49   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
                   ` (11 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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>
Message-ID: <20260803124040.126471-3-imbrenda@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@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] 47+ messages in thread

* [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (11 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 12/23] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 16:54   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
                   ` (10 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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>
Message-ID: <20260803124040.126471-4-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] 47+ messages in thread

* [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (12 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:03   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
                   ` (9 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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.

Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Fixes: abf4a71ed95f ("KVM: s390: Unlink vcpu on destroy - v2")
[ Added Fixes tag while picking -- Claudio ]
Message-ID: <20260803124040.126471-5-imbrenda@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 7514d9e2403c..bb4e72466043 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] 47+ messages in thread

* [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call()
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (13 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:09   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
                   ` (8 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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.

Fixes: 7d43bafcff17 ("KVM: s390: Make provisions for ESCA utilization")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-6-imbrenda@linux.ibm.com>
---
 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 bb4e72466043..8f24bcd1a6d3 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] 47+ messages in thread

* [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (14 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:14   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 17/23] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
                   ` (7 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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>
Message-ID: <20260803124040.126471-7-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] 47+ messages in thread

* [GIT PULL v1 17/23] KVM: s390: Fix race in __do_essa()
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (15 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:04   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
                   ` (6 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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>
Message-ID: <20260803124040.126471-8-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] 47+ messages in thread

* [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (16 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 17/23] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:12   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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>
Message-ID: <20260803124040.126471-9-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] 47+ messages in thread

* [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (17 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:19   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 20/23] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-10-imbrenda@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] 47+ messages in thread

* [GIT PULL v1 20/23] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (18 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:13   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 21/23] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
                   ` (3 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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.

Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-11-imbrenda@linux.ibm.com>
---
 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] 47+ messages in thread

* [GIT PULL v1 21/23] KVM: s390: Return -EINTR if a signal is pending while faulting-in
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (19 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 20/23] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:40   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 22/23] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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.

Fixes: e907ae530133 ("KVM: s390: Add helper functions for fault handling")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-12-imbrenda@linux.ibm.com>
---
 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] 47+ messages in thread

* [GIT PULL v1 22/23] KVM: s390: Fix ordering when adding to SCA
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (20 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 21/23] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:26   ` sashiko-bot
  2026-08-03 16:09 ` [GIT PULL v1 23/23] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
  2026-08-06 13:48 ` [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Paolo Bonzini
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-13-imbrenda@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] 47+ messages in thread

* [GIT PULL v1 23/23] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (21 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 22/23] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
@ 2026-08-03 16:09 ` Claudio Imbrenda
  2026-08-03 17:19   ` sashiko-bot
  2026-08-06 13:48 ` [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Paolo Bonzini
  23 siblings, 1 reply; 47+ messages in thread
From: Claudio Imbrenda @ 2026-08-03 16:09 UTC (permalink / raw)
  To: pbonzini; +Cc: kvm, linux-s390, frankja, borntraeger

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")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Message-ID: <20260803124040.126471-14-imbrenda@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] 47+ messages in thread

* Re: [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant
  2026-08-03 16:09 ` [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant Claudio Imbrenda
@ 2026-08-03 16:24   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:24 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: kvm, Vasily Gorbik, linux-s390, Heiko Carstens, Alexander Gordeev

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Guest memory over-read in get_guest_idal() for Format-1 IDALs requests twice the actual size of the guest's IDAL, potentially causing valid channel programs to be rejected.
- [High] When processing a CCW with the SKIP flag and IDA flag, the driver fails to translate the guest IDAWs into valid host physical addresses, potentially causing a host Channel Program Check.
--

--- Patch [4]: [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant ---
commit fb0447391e53154ceda5e61ab696ff1e49d88abb
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Ensure first IDAW remains constant

The first IDAW in a list does not need to be on a 2K/4K boundary
like all others, and so is read separately to accurately calculate
the size of the buffer needed to read the full IDAL. Verify that
the address found in the first IDAW is unchanged between reads,
to ensure a consistent set of IDAWs being worked with.

Cc: stable@vger.kernel.org

> diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
> index af632f9d54535..6275794751cb4 100644
> --- a/drivers/s390/cio/vfio_ccw_cp.c
> +++ b/drivers/s390/cio/vfio_ccw_cp.c
> @@ -523,6 +523,7 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
>  		&container_of(cp, struct vfio_ccw_private, cp)->vdev;
>  	dma64_t *idaws;
>  	dma32_t *idaws_f1;
> +	u64 first_idaw;
>  	int idal_len = idaw_nr * sizeof(*idaws);

[Severity: High]
This isn't a bug introduced by this patch, but does this over-calculate the
length for Format-1 IDALs?

Since Format-1 IDAWs are only 4 bytes long, but sizeof(*idaws) is 8 bytes,
idal_len ends up being twice the actual size.

When vfio_dma_rw() is called a few lines later:

    ret = vfio_dma_rw(vdev, dma32_to_u32(ccw->cda), idaws, idal_len, false);

could this attempt to read past the allocated IDAL size in guest memory? If
the over-read crosses into an unmapped page, it might spuriously reject a
valid guest channel program.

[ ... ]

I also noticed another issue in the same file.

[Severity: High]
This is a pre-existing issue, but do we correctly handle guest IDAW
translation when a CCW has both the SKIP and IDA flags set?

For such commands, ccw_does_data_transfer() returns 0, bypassing page
pinning:

drivers/s390/cio/vfio_ccw_cp.c:ccwchain_fetch_ccw() {
    ...
    if (!ccw_does_data_transfer(ccw)) {
        ...
        pa->pa_nr = 0;
    }
    ...
    page_array_idal_create_words(pa, idaws);
}

Because pa->pa_nr is 0, page_array_idal_create_words() returns without doing
anything, leaving the raw guest virtual addresses (IOVAs) in the idaws array.

Will the host channel subsystem hardware fetch these invalid physical
addresses and raise an access exception (Program Check), failing the valid
guest request?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=4

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type
  2026-08-03 16:09 ` [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type Claudio Imbrenda
@ 2026-08-03 16:24   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:24 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Alexander Gordeev, linux-s390, Vasily Gorbik, kvm, Heiko Carstens

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Untranslated guest physical addresses (or garbage data) are passed to the physical host channel subsystem for skipped commands, causing spurious channel-program checks.
--

--- Patch [5]: [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type ---
commit e748c56d38e70498395b0ca91606fb9902835452
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Calculate idal length based on idaw type

This commit fixes the guest IDAL length calculation in get_guest_idal() by
ensuring the size is based on the IDAW type (Format-1 vs Format-2) rather
than unconditionally assuming Format-2 (64-bit).

Link: https://lore.kernel.org/r/20260720203400.7328E1F000E9@smtp.kernel.org/

> diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
> index 6275794751cb4..5ef082b8289af 100644
> --- a/drivers/s390/cio/vfio_ccw_cp.c
> +++ b/drivers/s390/cio/vfio_ccw_cp.c
> @@ -233,6 +233,7 @@ static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
>  }
>  
>  #define idal_is_2k(_cp) (!(_cp)->orb.cmd.c64 || (_cp)->orb.cmd.i2k)
> +#define get_idaw_size(_cp) ((_cp)->orb.cmd.c64 ? sizeof(u64) : sizeof(u32))
>  
>  /*
>   * Helpers to operate ccwchain.

[ ... ]

> @@ -593,7 +594,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
>  	struct vfio_device *vdev =
>  		&container_of(cp, struct vfio_ccw_private, cp)->vdev;
>  	u64 iova;
> -	int size = cp->orb.cmd.c64 ? sizeof(u64) : sizeof(u32);
> +	int size = get_idaw_size(cp);
>  	int ret;
>  	int bytes = 1;

[Severity: High]
This is a pre-existing issue, but looking at ccwchain_fetch_ccw() in this
same file, there appears to be a problem when evaluating skipped commands:

drivers/s390/cio/vfio_ccw_cp.c:ccwchain_fetch_ccw() {
    ...
	if (ccw_does_data_transfer(ccw)) {
		ret = page_array_pin(pa, vdev, idal_is_2k(cp));
		if (ret < 0)
			goto out_unpin;
	} else {
		pa->pa_nr = 0;
	}

	ccw->cda = virt_to_dma32(idaws);
	ccw->flags |= CCW_FLAG_IDA;

	/* Populate the IDAL with pinned/translated addresses from page */
	page_array_idal_create_words(pa, idaws);
    ...
}

When pa->pa_nr is 0 for a command that does not transfer data (such as a
read with the SKIP flag set), page_array_idal_create_words() will perform
no operations.

Since ccw->cda is unconditionally set to the idaws array and CCW_FLAG_IDA
is set, does this cause the host channel subsystem to fetch untranslated
guest physical addresses (or garbage data)?

For skipped read operations, the s390 hardware architecture still requires
IDAWs to be fetched and validity checked. Could this result in spurious
channel-program checks being injected into valid guest I/O operations?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=5

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails
  2026-08-03 16:09 ` [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails Claudio Imbrenda
@ 2026-08-03 16:28   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:28 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: linux-s390, kvm, Alexander Gordeev, Heiko Carstens, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] A malicious guest can trigger unbounded kernel stack recursion and host panic by providing a long chain of non-looping Transfer in Channel (TIC) CCWs.
--

--- Patch [1]: [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails ---
commit 2ed68383152f2b2060167f3fc63cdb973d979950
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Free all memory if cp_init() fails

This commit moves the ccwchain cleanup out of the recursive
ccwchain_handle_ccw() and ccwchain_loop_tic() logic into a new wrapper
function ccwchain_build_ccws(). This ensures that all segments allocated for
a channel program are freed if initialization fails.

> diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
> index 7561aa7d3e017..086d1b54bdb05 100644
> --- a/drivers/s390/cio/vfio_ccw_cp.c
> +++ b/drivers/s390/cio/vfio_ccw_cp.c
[ ... ]
> @@ -455,9 +455,6 @@ static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
>  	/* Loop for tics on this new chain. */
>  	ret = ccwchain_loop_tic(chain, cp);
>  

[Severity: High]
This is a pre-existing issue, but can this recursive call chain lead to
unbounded kernel stack consumption?

Looking at ccwchain_handle_ccw() and ccwchain_loop_tic(), they recursively
call each other:

ccwchain_handle_ccw()
   ccwchain_loop_tic()
      ccwchain_handle_ccw()

If a guest constructs a channel program with a long sequence of Transfer
in Channel (TIC) CCWs, where each points to a distinct guest physical
address, tic_target_chain_exists() will return false.

Does this allow an unprivileged guest to trigger unbounded recursion and
overflow the host kernel stack, resulting in a host panic?

> -	if (ret)
> -		ccwchain_free(chain);
> -
>  	return ret;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=1

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments
  2026-08-03 16:09 ` [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments Claudio Imbrenda
@ 2026-08-03 16:32   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:32 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: linux-s390, Vasily Gorbik, Heiko Carstens, Alexander Gordeev, kvm

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Sleeping in atomic context when processing NOT_OPER FSM event
- [High] Race condition leading to Use-After-Free / list corruption on channel program
- [High] Out-of-bounds read in ccwchain_calc_length
--

--- Patch [2]: [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments ---
commit f04946000e5f4fc0876ae6db794b58a1b8744e08
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Limit the number of channel program segments

The processing of channel programs, and the CCWs within them, is done
recursively. As such, there is an arbitrary (but not architectural)
limit to the number of CCWs that can exist in a single channel program.

The vfio-ccw logic breaks these channel programs into segments whenever
it encounters a Transfer-In-Channel (TIC) CCW, and the combined number
of segments count towards the global limit. Impose an equivalent limit
to the number of segments until such logic can be made non-recursive.

> diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
> index 086d1b54bdb05..1c2890d139c6b 100644
> --- a/drivers/s390/cio/vfio_ccw_cp.c
> +++ b/drivers/s390/cio/vfio_ccw_cp.c
[ ... ]
> @@ -441,6 +442,10 @@ static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
>  	if (len < 0)
>  		return len;

[Severity: High]
This is a pre-existing issue, but can the call to ccwchain_calc_length() just
before this block result in an out-of-bounds read?

If a guest provides a channel program with 256 command-chained CCWs, the loop
in ccwchain_calc_length() reaches cnt == 256 and increments the ccw pointer
past the end of the array.

The loop condition while (cnt < CCWCHAIN_LEN_MAX + 1) then allows a 257th
iteration, which dereferences the out-of-bounds ccw pointer in the
ccw_is_chain(ccw) check.

> +	/* Limit number of chains in a single channel program */
> +	if (cp->ccwchain_count >= CCWCHAIN_COUNT_MAX)
> +		return -EINVAL;
> +
>  	/* Need alloc a new chain for this one. */
>  	chain = ccwchain_alloc(cp, len);
>  	if (!chain)
[ ... ]
> @@ -745,6 +750,7 @@ int cp_init(struct channel_program *cp, union orb *orb)
>  			vdev->dev,
>  			"Prefetching channel program even though prefetch not specified in ORB");
>  
> +	cp->ccwchain_count = 0;
>  	INIT_LIST_HEAD(&cp->ccwchain_list);
>  	memcpy(&cp->orb, orb, sizeof(*orb));

[Severity: High]
This is a pre-existing issue, but could this channel program initialization
race with a subchannel event, leading to a use-after-free or list corruption?

The I/O request path holds private->io_mutex and initializes or modifies
private->cp in fsm_io_request(). Concurrently, the subchannel event path
(like a device offline event) holds sch->lock and unconditionally frees
private->cp in fsm_notoper().

Since the two contexts use disjoint locks, is there anything preventing them
from racing?

[Severity: High]
This is another pre-existing issue, but can fsm_notoper() sleep while holding
a spinlock with interrupts disabled?

When a subchannel event occurs, vfio_ccw_sch_event() acquires sch->lock using
spin_lock_irqsave(). It then calls vfio_ccw_fsm_event(), which executes
fsm_notoper().

fsm_notoper() calls cp_free(), which can eventually reach
vfio_iommu_type1_unpin_pages(). That function acquires a sleepable mutex:

drivers/vfio/vfio_iommu_type1.c:vfio_iommu_type1_unpin_pages()
    ...
    mutex_lock(&iommu->lock);
    ...

Could this lead to a deadlock or crash if triggered by hardware or
virtualization events while a guest is operating?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=2

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range
  2026-08-03 16:09 ` [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range Claudio Imbrenda
@ 2026-08-03 16:34   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:34 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: linux-s390, Vasily Gorbik, Heiko Carstens, kvm, Alexander Gordeev

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [Critical] The `private->crw` linked list is accessed and modified concurrently without any synchronization, leading to list corruption.
--

--- Patch [6]: [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range ---
commit e1d18d0b96d197063d1125d864eec65df5351f67
Author: Eric Farman <farman@linux.ibm.com>

    s390/vfio_ccw: Ensure index for read/write regions are within range
    
    The introduction of the capability chain rightly clamped the
    region indexes to the range of the capabilities itself, but
    neglected to do so for the existing read/write regions which
    should also be enforced.

[ ... ]

> diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
> index 38c176cf62957..f3015132d4b5f 100644
> --- a/drivers/s390/cio/vfio_ccw_chp.c
> +++ b/drivers/s390/cio/vfio_ccw_chp.c

[ ... ]

> @@ -97,6 +105,12 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
>  		list_del(&crw->next);
>  

[Severity: Critical]
This is a pre-existing issue, but does this code corrupt the private->crw list?

CRW events are dequeued from the list here without any lock protection, allowing
concurrent read() syscalls to race and corrupt the list.

It looks like events are also appended to the list locklessly by
vfio_ccw_queue_crw():

drivers/s390/cio/vfio_ccw_drv.c:vfio_ccw_queue_crw() {
	...
	list_add_tail(&crw->next, &private->crw);
	queue_work(vfio_ccw_work_q, &private->crw_work);
}

This means a single read() call can race against an incoming channel path event
handled by the asynchronous CSS callback vfio_ccw_chp_event(), resulting in list
corruption.

>  	mutex_lock(&private->io_mutex);
> +	if (i >= private->num_regions) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	i = array_index_nospec(i, private->num_regions);
>  	region = private->region[i].data;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=6

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational
  2026-08-03 16:09 ` [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational Claudio Imbrenda
@ 2026-08-03 16:39   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:39 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, linux-s390, Vasily Gorbik, kvm, Alexander Gordeev

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Concurrent execution of `cp_free()` can lead to a double-free of channel program resources due to missing locking.
- [High] A TOCTOU race between subchannel events and mdev removal allows an asynchronous event to queue work on a freed vfio_ccw_private structure.
--

--- Patch [8]: [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational ---
commit aa01cda35a6813e56642eb80e4a1779189d3de13
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Move cp cleanup out of not operational

This commit moves the cleanup of channel program resources out of the
not-operational state machine event and defers it to a workqueue. This avoids
potential locking issues with the cio subchannel lock when the device is lost.

> diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
> index 1a095085bc728..c197ad5ab5805 100644
> --- a/drivers/s390/cio/vfio_ccw_drv.c
> +++ b/drivers/s390/cio/vfio_ccw_drv.c

[ ... ]

> @@ -125,6 +125,15 @@ void vfio_ccw_crw_todo(struct work_struct *work)
>  		eventfd_signal(private->crw_trigger);
>  }
>  
> +void vfio_ccw_notoper_todo(struct work_struct *work)
> +{
> +	struct vfio_ccw_private *private;
> +
> +	private = container_of(work, struct vfio_ccw_private, notoper_work);
> +
> +	cp_free(&private->cp);

[Severity: High]
This is a pre-existing issue, but making the cleanup asynchronous
significantly widens the vulnerability window for a double-free.

Since vfio_ccw_notoper_todo() does not acquire io_mutex before calling
cp_free(), what happens if userspace concurrently closes the VFIO device file
descriptor?

If a device becomes not-operational, triggering vfio_ccw_sch_event() which
queues vfio_ccw_notoper_todo(), and concurrently vfio_ccw_mdev_close_device()
calls fsm_close() -> cp_free(), both threads could enter cp_free()
simultaneously.

Because the !cp->initialized check in drivers/s390/cio/vfio_ccw_cp.c:cp_free()
is non-atomic, both threads could bypass it and proceed to double-free the
channel program resources.

Could we acquire private->io_mutex before calling cp_free() here?

> +}

[ ... ]

> diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
> index 4d7988ea47ef0..4d47a3c7b9a06 100644
> --- a/drivers/s390/cio/vfio_ccw_fsm.c
> +++ b/drivers/s390/cio/vfio_ccw_fsm.c
> @@ -170,8 +170,7 @@ static void fsm_notoper(struct vfio_ccw_private *private,
>  	css_sched_sch_todo(sch, SCH_TODO_UNREG);
>  	private->state = VFIO_CCW_STATE_NOT_OPER;
>  
> -	/* This is usually handled during CLOSE event */
> -	cp_free(&private->cp);
> +	queue_work(vfio_ccw_work_q, &private->notoper_work);

[Severity: High]
This isn't a bug introduced by this patch, but transforming this cleanup into
a queue_work() call exposes a specific use-after-free vector via a TOCTOU
race.

Looking at vfio_ccw_sch_event() in drivers/s390/cio/vfio_ccw_drv.c, the
private pointer is read locklessly via dev_get_drvdata(). If the thread is
preempted after obtaining this pointer, could a concurrent sysfs mdev_remove
call execute vfio_ccw_mdev_remove()?

If vfio_ccw_mdev_remove() clears the drvdata, flushes workqueues, and drops
the final reference to private, the memory is freed.

When vfio_ccw_sch_event() resumes, it would dereference the freed private
pointer to call fsm_notoper(), which then executes queue_work() on the freed
memory, potentially corrupting the global system workqueue.

Is there a way to ensure the lifetime of the private structure during this
event processing?

>  }
>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=8

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues
  2026-08-03 16:09 ` [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues Claudio Imbrenda
@ 2026-08-03 16:41   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:41 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Alexander Gordeev, linux-s390, kvm, Heiko Carstens, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

Pre-existing issues:
- [High] Double-free and use-after-free of channel program structures due to concurrent execution of `cp_free()`.
- [High] Use-after-free of `vfio_ccw_private` due to concurrent execution of `vfio_ccw_mdev_remove()` and `vfio_ccw_chp_event()`.
- [High] Data race and linked list corruption of `private->crw`.
- [High] Use-after-free of `eventfd_ctx` due to lack of synchronization in `vfio_ccw_mdev_set_irqs()`.
--

--- Patch [7]: [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues ---
commit 9c72e034f4d8d6193d6ae49cecd7dc50eda41903
Author: Eric Farman <farman@linux.ibm.com>
Subject: s390/vfio_ccw: Cancel existing workqueues

The initialization of the io_work and crw_work workqueues begs the
question of whether they should be un-initialized. Add the corresponding
cleanup tags in _release_dev to ensure work isn't dispatched after
the private struct is free'd.

> diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
> index 032a1cdf4df70..d361d1fde3a0d 100644
> --- a/drivers/s390/cio/vfio_ccw_ops.c
> +++ b/drivers/s390/cio/vfio_ccw_ops.c
> @@ -131,6 +131,13 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
>  		container_of(vdev, struct vfio_ccw_private, vdev);
>  	struct vfio_ccw_crw *crw, *temp;
>  
> +	/*
> +	 * Ensure these work items are fully drained, so none can
> +	 * fire after being released.
> +	 */
> +	cancel_work_sync(&private->io_work);
> +	cancel_work_sync(&private->crw_work);

[Severity: High]
This is a pre-existing issue, but does this cancellation prevent subsequent
queuing if vfio_ccw_chp_event() races with vfio_ccw_mdev_remove()?

vfio_ccw_chp_event() reads private locklessly before it is cleared and
prepares to queue work:

drivers/s390/cio/vfio_ccw_drv.c:vfio_ccw_chp_event() {
    struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
    ...
        vfio_ccw_queue_crw(private, CRW_RSC_CPATH, CRW_ERC_PERRN,
                           link->chpid.id);
}

If vfio_ccw_mdev_remove() concurrently clears the driver data, releases the
device, and drains the currently empty workqueue via
cancel_work_sync(&private->crw_work), can vfio_ccw_chp_event() subsequently
queue work on the freed private object, leading to a use-after-free when
vfio_ccw_crw_todo() executes?

>  	list_for_each_entry_safe(crw, temp, &private->crw, next) {

[Severity: High]
This is a pre-existing issue, but is the private->crw linked list protected
against concurrent modifications here?

vfio_ccw_queue_crw() appends elements to the list with list_add_tail() while
holding sch->lock. Concurrently, userspace triggering a read on the CRW
region invokes vfio_ccw_crw_region_read(), which locklessly calls
list_first_entry_or_null() and list_del() before acquiring
private->io_mutex:

drivers/s390/cio/vfio_ccw_chp.c:vfio_ccw_crw_region_read() {
    ...
    crw = list_first_entry_or_null(&private->crw,
                                   struct vfio_ccw_crw, next);
    if (crw)
        list_del(&crw->next);
    mutex_lock(&private->io_mutex);
}

Can multiple concurrent reads, or a read concurrent with an asynchronous
channel path event, corrupt the list pointers?

>  		list_del(&crw->next);
>  		kfree(crw);
>  	}

[ ... ]

> @@ -202,6 +209,14 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)
>  		container_of(vdev, struct vfio_ccw_private, vdev);
>  
>  	vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
> +
> +	/*
> +	 * Ensure these work items are drained, in the event the
> +	 * device is re-opened instead of released.
> +	 */
> +	cancel_work_sync(&private->io_work);

[Severity: High]
This is a pre-existing issue, but does placing cancel_work_sync() after
vfio_ccw_fsm_event() leave a double-free race intact?

The device is closed via vfio_ccw_mdev_close_device(), which triggers the
FSM CLOSE event and calls fsm_close(). fsm_close() invokes cp_free()
entirely locklessly:

drivers/s390/cio/vfio_ccw_fsm.c:fsm_close() {
    ...
    spin_unlock_irq(&sch->lock);
    cp_free(&private->cp);
}

Concurrently, if the io_work workqueue is already running
vfio_ccw_sch_io_todo(), it locklessly evaluates
private->state == VFIO_CCW_STATE_CP_PENDING and also calls cp_free():

drivers/s390/cio/vfio_ccw_drv.c:vfio_ccw_sch_io_todo() {
    ...
    if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) {
        cp_free(&private->cp);
    ...
}

Since the new cancel_work_sync(&private->io_work) executes after the FSM
event, can io_work still execute concurrently with the FSM close handler
and double-free the channel program structures?

[Severity: High]
This isn't a bug introduced by this patch, but does the lack of
synchronization in vfio_ccw_mdev_set_irqs() allow a use-after-free of the
eventfd_ctx object?

In vfio_ccw_mdev_set_irqs(), userspace can unregister an eventfd, executing
eventfd_ctx_put(*ctx):

drivers/s390/cio/vfio_ccw_ops.c:vfio_ccw_mdev_set_irqs() {
    ...
        if (fd == -1) {
            if (*ctx)
                eventfd_ctx_put(*ctx);
            *ctx = NULL;
        }
}

There appear to be no locks preventing the workqueue from concurrently
reading private->io_trigger. If vfio_ccw_sch_io_todo() reads the pointer
locklessly:

drivers/s390/cio/vfio_ccw_drv.c:vfio_ccw_sch_io_todo() {
    ...
    if (private->io_trigger)
        eventfd_signal(private->io_trigger);
}

Can the workqueue execute eventfd_signal() on freed memory if
vfio_ccw_mdev_set_irqs() frees the context after it was read but before it
is signaled?

> +	cancel_work_sync(&private->crw_work);
> +
>  	vfio_ccw_unregister_dev_regions(private);
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=7

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 11/23] KVM: s390: Fix unlikely NULL gmap dereference
  2026-08-03 16:09 ` [GIT PULL v1 11/23] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
@ 2026-08-03 16:43   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:43 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, linux-s390, 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")
> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
> Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
> Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
> 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/20260803160924.236807-1-imbrenda@linux.ibm.com?part=11


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 12/23] KVM: s390: Do not free SCA if it was not allocated
  2026-08-03 16:09 ` [GIT PULL v1 12/23] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
@ 2026-08-03 16:49   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:49 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, linux-s390, Vasily Gorbik, Alexander Gordeev, kvm

> 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/20260803160924.236807-1-imbrenda@linux.ibm.com?part=12


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock
  2026-08-03 16:09 ` [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock Claudio Imbrenda
@ 2026-08-03 16:51   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:51 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: kvm, Heiko Carstens, Alexander Gordeev, linux-s390, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing synchronization when updating eventfd triggers leads to a potential Use-After-Free of the `eventfd_ctx` during `eventfd_signal()`.
- [High] Concurrent execution of asynchronous CSS hardware callbacks and mdev removal allows a Use-After-Free of the `vfio_ccw_private` structure.
- [Medium] The `eventfd_ctx` for device triggers is leaked when the device file descriptor is closed without explicitly disabling the IRQs.
--

--- Patch [10]: [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock ---
commit e6c7aa37724a25bba44b60d5d9939f115e04276a
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Implement a crw lock

Unlike the channel_program struct, which covers synchronous I/O
submissions and asynchronous interrupts, the CRW region relies
exclusively on asynchronous events coming from hardware.

Implement a lock to manage the list of those payloads, to ensure
they are read cohesively.

Cc: stable@vger.kernel.org

> diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
> index 757ff5b2556e3..ab6b518cc353f 100644
> --- a/drivers/s390/cio/vfio_ccw_drv.c
> +++ b/drivers/s390/cio/vfio_ccw_drv.c
> @@ -118,11 +118,14 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
>  void vfio_ccw_crw_todo(struct work_struct *work)
>  {
>  	struct vfio_ccw_private *private;
> +	unsigned long flags;
>  
>  	private = container_of(work, struct vfio_ccw_private, crw_work);
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
>  	if (!list_empty(&private->crw) && private->crw_trigger)
>  		eventfd_signal(private->crw_trigger);
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
>  }

[Severity: High]
This is a pre-existing issue, but does this adequately protect against
concurrent modification of the eventfd context?

While this patch adds crw_lock around the read and signal path here in
vfio_ccw_crw_todo(), is the writer side in vfio_ccw_mdev_set_irqs()
also protected?

If vfio_ccw_mdev_set_irqs() replaces or unsets the eventfd without locks:

vfio_ccw_mdev_set_irqs()
    if (*ctx)
        eventfd_ctx_put(*ctx);
    *ctx = efdctx;
    
Could a concurrent execution of vfio_ccw_crw_todo() read the pointer,
have the context freed by vfio_ccw_mdev_set_irqs(), and then use it in
eventfd_signal(), resulting in a use-after-free?

[ ... ]

> @@ -286,6 +289,7 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
>  			       unsigned int rsid)
>  {
>  	struct vfio_ccw_crw *crw;
> +	unsigned long flags;
>  
>  	/*
>  	 * If unable to allocate a CRW, just drop the event and
>  	 * carry on.  The guest will either see a later one or
>  	 * learn when it issues its own store subchannel.
>  	 */
>  	crw = kzalloc_obj(*crw, GFP_ATOMIC);
>  	if (!crw)
>  		return;
>  
>  	/*
>  	 * Build the CRW based on the inputs given to us.
>  	 */
>  	crw->crw.rsc = rsc;
>  	crw->crw.erc = erc;
>  	crw->crw.rsid = rsid;
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
>  	list_add_tail(&crw->next, &private->crw);
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
>  	queue_work(vfio_ccw_work_q, &private->crw_work);
>  }

[Severity: High]
This is a pre-existing issue, but could vfio_ccw_queue_crw() dereference
a freed private pointer during device removal?

If an asynchronous CSS hardware callback like vfio_ccw_chp_event() fetches
the private struct locklessly, and concurrently the mdev is removed via
sysfs:

vfio_ccw_mdev_remove()
    dev_set_drvdata(&parent->dev, NULL);
    vfio_put_device(&private->vdev);
    
Since there is no synchronization stopping the CSS callback, could the
private structure be freed before vfio_ccw_chp_event() calls
vfio_ccw_queue_crw(), leading to a use-after-free when acquiring the
crw_lock here?

[ ... ]

> diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
> index 1df6d649565b8..5ce91285c7d52 100644
> --- a/drivers/s390/cio/vfio_ccw_ops.c
> +++ b/drivers/s390/cio/vfio_ccw_ops.c
> @@ -131,6 +132,7 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
>  	struct vfio_ccw_private *private =
>  		container_of(vdev, struct vfio_ccw_private, vdev);
>  	struct vfio_ccw_crw *crw, *temp;
> +	unsigned long flags;
>  
>  	/*
>  	 * Ensure these work items are fully drained, so none can
> @@ -146,10 +148,12 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
>  	cancel_work_sync(&private->crw_work);
>  	flush_work(&private->notoper_work);
>  
> +	spin_lock_irqsave(&private->crw_lock, flags);
>  	list_for_each_entry_safe(crw, temp, &private->crw, next) {
>  		list_del(&crw->next);
>  		kfree(crw);
>  	}
> +	spin_unlock_irqrestore(&private->crw_lock, flags);
>  
>  	kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
>  	kmem_cache_free(vfio_ccw_schib_region, private->schib_region);

[Severity: Medium]
This isn't a bug introduced by this patch, but does closing the device leak
the eventfd contexts allocated for device triggers?

When userspace configures IRQs via VFIO_DEVICE_SET_IRQS, eventfd_ctx_fdget()
increments the reference count of the eventfd context.

If userspace closes the device without explicitly disabling the IRQs first,
vfio_ccw_mdev_release_dev() is invoked. Is it necessary to call
eventfd_ctx_put() here to release the references to private->io_trigger,
private->crw_trigger, and private->req_trigger?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=10

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex
  2026-08-03 16:09 ` [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex Claudio Imbrenda
@ 2026-08-03 16:54   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:54 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Alexander Gordeev, Heiko Carstens, kvm, Vasily Gorbik, linux-s390

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Concurrent modification of the `private->crw` linked list without proper synchronization, risking list corruption.
- [High] Missing synchronization between CSS callbacks and `vfio_ccw_mdev_remove()` causes use-after-free of `private`.
- [Medium] Valid CRW events are permanently dropped and lost if userspace provides an invalid read offset.
--

--- Patch [9]: [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex ---
commit 0dffa46dd03162ef88bfa6bbfa42490f8f336394
Author: Eric Farman <farman@linux.ibm.com>

s390/vfio_ccw: Selectively expand io_mutex

The io_mutex was defined to serialize the io_regions, but then has
also sort of been associated with the I/O themselves because of
the close relationship they share. This patch expands the scope of
io_mutex to close these remaining windows.

Cc: stable@vger.kernel.org

> diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
> index f3015132d4b5f..9269b54f5cfd4 100644
> --- a/drivers/s390/cio/vfio_ccw_chp.c
> +++ b/drivers/s390/cio/vfio_ccw_chp.c
> @@ -98,13 +98,13 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
>  	if (pos + count > sizeof(*region))
>  		return -EINVAL;
>  
> +	mutex_lock(&private->io_mutex);
>  	crw = list_first_entry_or_null(&private->crw,
>  				       struct vfio_ccw_crw, next);
>  
>  	if (crw)
>  		list_del(&crw->next);

[Severity: High]
This isn't a bug introduced by this patch, but does this list_del() lack
proper synchronization?

It appears vfio_ccw_crw_region_read() dequeues from private->crw while
only holding the sleepable io_mutex. If an atomic channel path event
triggers vfio_ccw_chp_event() concurrently, it will call
vfio_ccw_queue_crw(), which locklessly adds to private->crw using
list_add_tail().

Since io_mutex is ignored by the atomic queue path, can this concurrent
access corrupt the linked list if userspace aggressively reads the CRW
region while hardware events are generated?

> -	mutex_lock(&private->io_mutex);
>  	if (i >= private->num_regions) {
>  		ret = -EINVAL;
>  		goto out;
>  	}

[Severity: Medium]
This is a pre-existing issue, but are valid CRW events permanently dropped
if userspace provides an invalid read offset?

The bounds check for the region index occurs after the event has already
been dequeued from private->crw. If the offset is invalid, the event seems
to be discarded and later freed on failure without delivery.

Should state mutations happen after all arguments are validated to prevent
this resource loss?

[ ... ]
> diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
> index c197ad5ab5805..757ff5b2556e3 100644
> --- a/drivers/s390/cio/vfio_ccw_drv.c
> +++ b/drivers/s390/cio/vfio_ccw_drv.c
[ ... ]

[Severity: High]
This is a pre-existing issue, but is there a missing synchronization step
between CSS callbacks and vfio_ccw_mdev_remove() that causes a
use-after-free?

In drivers/s390/cio/vfio_ccw_ops.c, vfio_ccw_mdev_remove() clears drvdata
and drops the final reference to the device:

vfio_ccw_mdev_remove() {
    ...
    dev_set_drvdata(&parent->dev, NULL);
    vfio_put_device(&private->vdev);
}

If an administrator initiates an mdev removal concurrently with a hardware
event, vfio_ccw_sch_event() in drivers/s390/cio/vfio_ccw_drv.c reads the
private pointer locklessly via dev_get_drvdata():

vfio_ccw_sch_event() {
    ...
    struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
}

If the CSS callback is delayed after reading the pointer, could it execute
vfio_ccw_fsm_event() on the freed private structure?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=9

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
  2026-08-03 16:09 ` [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
@ 2026-08-03 16:54   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 16:54 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Alexander Gordeev, Vasily Gorbik, Heiko Carstens, kvm, linux-s390

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] Unrecoverable memory leak of `vcpu->arch.mc` during vCPU creation failure in `kvm_arch_vcpu_create()`.
- [High] Leaked `stor_base` and `sida_addr` memory pages when Protected Virtualization (PV) vCPU creation fails.
--

--- Patch [13]: [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() ---
commit 4fc054529959a7d0bf80c4a0b469e82c4a224bb3
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>

KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma()
    
This commit fixes an issue where a zero cbrlo value could lead to an attempt
to free physical page 0 when V != R. It resolves this by checking that cbrlo
is non-zero before calling free_page().

Link: <20260803124040.126471-4-imbrenda@linux.ibm.com>

> 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 while reviewing the vCPU
creation paths in this subsystem, I noticed a potential unrecoverable memory
leak.

In arch/s390/kvm/kvm-s390.c:kvm_arch_vcpu_create(), the mmu cache is
successfully allocated:

    vcpu->arch.mc = kvm_s390_new_mmu_cache();

However, if a subsequent operation fails and the function jumps to the error
path, it appears to miss freeing the cache:

    out_free_sie_block:
        free_page((unsigned long)(vcpu->arch.sie_block));
        return rc;

Does this leak the struct kvm_s390_mmu_cache and its internal allocations
when the core KVM code skips calling kvm_arch_vcpu_destroy() on an
arch-level creation failure?

[Severity: High]
This is also a pre-existing issue, but looking at the Protected
Virtualization code in arch/s390/kvm/pv.c, there might be another memory
leak during vCPU creation failure.

In kvm_s390_pv_create_cpu(), if the UV call fails, it attempts to clean up:

    if (cc) {
        u16 dummy;

        kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
        return -EIO;
    }

Because the handle is only populated upon success, it is still 0 during this
cleanup call. kvm_s390_pv_destroy_cpu() checks the handle and returns early:

    if (!kvm_s390_pv_cpu_get_handle(vcpu))
        return 0;

Could this leave the stor_base and sida_addr memory pages permanently leaked
if userspace repeatedly exhausts UV limits to fail the call?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=13

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error
  2026-08-03 16:09 ` [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
@ 2026-08-03 17:03   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:03 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, kvm, linux-s390, Vasily Gorbik, Alexander Gordeev

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Out-of-bounds memory accesses to the ESCA block for KVM_VM_S390_UCONTROL VMs with vcpu_id >= KVM_S390_ESCA_CPU_SLOTS (248).
- [High] Memory leak of `vcpu->arch.mc` in `kvm_arch_vcpu_create` error paths.
- [High] Memory leak of `stor_base` and `sidad` pages in `kvm_s390_pv_create_cpu` when Ultravisor call fails.
--

--- Patch [14]: [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error ---
commit d5a31a585e995dfd927fed9a3fff444b9b4d0db1
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, clearing its ESCA entry. This
commit skips clearing the ESCA entry if the vCPU creation was not
successful.

Message-ID: <20260803124040.126471-5-imbrenda@linux.ibm.com>

> 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)
>  		return;

[Severity: High]
This is a pre-existing issue, but does this function have an out-of-bounds
write if the VM is KVM_VM_S390_UCONTROL and the vcpu_id is >= 248?

If a user with CAP_SYS_ADMIN creates a ucontrol VM and initializes a vCPU
with a vcpu_id between 248 and 254, indexing into sca->cpu[vcpu->vcpu_id]
would be out of bounds since KVM_S390_ESCA_CPU_SLOTS is 248.

Functions like sca_clear_ext_call(), sca_inject_ext_call(), and
sca_ext_call_pending() appear to access this without bounds checking. Could
this corrupt adjacent memory pages?

[ ... ]

[Severity: High]
This is a pre-existing issue, but does kvm_arch_vcpu_create() leak
vcpu->arch.mc in the error path?

Looking at the error handling in 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;

If an error occurs during kvm_s390_vcpu_setup() and it jumps to
out_ucontrol_uninit, it appears kvm_s390_free_mmu_cache() is never called
before returning. Can userspace systematically leak the KVM MMU cache by
inducing vCPU setup failures?

[Severity: High]
This is a pre-existing issue, but does kvm_s390_pv_create_cpu() leak
stor_base and sidad pages when the Ultravisor call fails?

In kvm_s390_pv_create_cpu(), if the uv_call fails, it tries to clean up:

	if (cc) {
		u16 dummy;

		kvm_s390_pv_destroy_cpu(vcpu, &dummy, &dummy);
		return -EIO;
	}

However, kvm_s390_pv_destroy_cpu() checks the handle:

	if (!kvm_s390_pv_cpu_get_handle(vcpu))
		return 0;

Since vcpu->arch.pv.handle is populated only after a successful UV call,
this will return early. Does this bypass the free_pages() and free_page()
calls for stor_base and the SIDA, permanently leaking them?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=14

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 17/23] KVM: s390: Fix race in __do_essa()
  2026-08-03 16:09 ` [GIT PULL v1 17/23] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
@ 2026-08-03 17:04   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:04 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, Vasily Gorbik, kvm, linux-s390, Alexander Gordeev

> 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>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=17


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call()
  2026-08-03 16:09 ` [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
@ 2026-08-03 17:09   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:09 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: kvm, linux-s390, Heiko Carstens, Alexander Gordeev, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] UCONTROL VM external call injection fails or succeeds inconsistently depending on the host's hardware ESCA support.
--

--- Patch [15]: [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call() ---
commit 4cf53d54c2a9bad47bf30203ae51ce4109c4612e
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>

KVM: s390: ucontrol: Fix sca_clear_ext_call()

This commit addresses an issue where cleaning up a UCONTROL VM would touch
memory outside of the allocated ESCA block. It fixes this by avoiding ESCA
access for UCONTROL VMs and fencing the KVM_S390_INTERRUPT ioctl for them.

> 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
> @@ -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;

[Severity: Medium]
Will this cause pending software external calls to be ignored on hosts with
ESCA?

If the host supports ESCA and kvm_s390_use_sca_entries() is true, the system
will rely on sca_ext_call_pending(). By returning 0 here for UCONTROL VMs,
won't any pending software external calls be ignored?

[ ... ]

> @@ -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]
Does this create an ABI inconsistency where UCONTROL VMs behave differently
based on the host's hardware capabilities?

When userspace calls the KVM_S390_IRQ ioctl on a UCONTROL VM to inject
KVM_S390_INT_EXTERNAL_CALL, __inject_extcall() checks 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 the host doesn't support ESCA, it bypasses sca_inject_ext_call() and
successfully queues the interrupt via the software fallback. 

But if the host does support ESCA, it calls sca_inject_ext_call() which
will now hit this check and return -EINVAL instead of queuing it.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=15

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot
  2026-08-03 16:09 ` [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
@ 2026-08-03 17:12   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:12 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Alexander Gordeev, Vasily Gorbik, linux-s390, Heiko Carstens, kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Mixing of `goto`-based error handling with scope-based cleanups (`__free()` and `guard()`).
--

--- Patch [18]: [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot ---
commit b4b4bb1a465e2a5c28c8cf71b60ac80548c5f396
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>

KVM: s390: cmma: Fix dirty tracking when removing memslot

This patch fixes CMMA dirty tracking when a memslot is removed during
migration mode. It also opportunistically updates the memory region commit
path to use the __free() cleanup helper for the 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
[ ... ]
>  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 code mix goto-based error handling with scope-based cleanups?

According to the guidelines in include/linux/cleanup.h, functions should
convert all resources that need a goto cleanup to scope-based cleanup,
or convert none of them. This function introduces guard() and __free()
declarations here, but it still retains the `out:` label and the `goto out;`
error path when kvm_s390_new_mmu_cache() fails.

Also, is it possible to combine the __free() declaration and initialization of
mc at the point of allocation? Declaring it at the top as = NULL and
assigning it later makes LIFO ordering mistakes more likely. Could the goto
path be replaced with a direct return, and the mc variable be defined where
it is first allocated?

[ ... ]
> @@ -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;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=18

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 20/23] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails
  2026-08-03 16:09 ` [GIT PULL v1 20/23] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
@ 2026-08-03 17:13   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:13 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Vasily Gorbik, Alexander Gordeev, linux-s390, kvm, Heiko Carstens

> 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.
> 
> 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/20260803160924.236807-1-imbrenda@linux.ibm.com?part=20


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
  2026-08-03 16:09 ` [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
@ 2026-08-03 17:14   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:14 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, linux-s390, Vasily Gorbik, Alexander Gordeev, kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] 1-bit kernel stack memory leak to userspace via uninitialized bitfield in union skey.
--

--- Patch [16]: [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace ---
commit 74696629bd13e2265747961c02030c7ac8a442d4
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>

    KVM: s390: Fix leaking of PGM_ADDRESSING to userspace
    
    If kvm_s390_set_cmma_bits() is asked to set CMMA values outside of a
    memslot, PGM_ADDRESSING (5) is returned, instead of a negative error
    value. Fix by returning -EFAULT whenever the return value would be > 0.

Link: https://lkml.kernel.org/r/20260803124040.126471-7-imbrenda@linux.ibm.com

> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 21574f57be72e..e162efaa35b8f 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;

[Severity: High]
This isn't a bug introduced by this patch, but does returning skey.skey here
leak uninitialized kernel stack memory to userspace?

Looking at dat_cond_set_storage_key() in arch/s390/kvm/dat.c, a local union
skey prev is declared without initialization:

	union skey prev;

When ptep->h.i is true, it assigns values to 4 of the 5 bitfields in prev,
but the zero bitfield remains uninitialized and retains kernel stack garbage:

	} else {
		prev.acc = old.acc;
		prev.fp = old.fp;
		prev.c = old.gc;
		prev.r = old.gr;
	}

This prev union is then copied to *oldkey:

	if (oldkey)
		*oldkey = prev;

Since oldkey points to the local skey variable here in kvm_s390_keyop(),
does returning skey.skey eventually leak this uninitialized zero bitfield to
userspace when the result is copied via copy_to_user()?

>  		break;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=16

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child()
  2026-08-03 16:09 ` [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
@ 2026-08-03 17:19   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:19 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, Vasily Gorbik, linux-s390, Alexander Gordeev, kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing cleanup of `vcpu->arch.mc` on error paths in `kvm_arch_vcpu_create`.
--

--- Patch [19]: [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() ---
commit 61cd1afcaa7879de84aab0c942311aadeeda9499
Author: Claudio Imbrenda <imbrenda@linux.ibm.com>

KVM: s390: ucontrol: Add missing locking around gmap_remove_child()

This commit adds missing locking around gmap_remove_child() 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 isn't a bug introduced by this patch, but does this error path leak
the mmu cache allocated for the vCPU?

In kvm_arch_vcpu_create() within arch/s390/kvm/kvm-s390.c, if an
unprivileged process repeatedly calls KVM_CREATE_VCPU near its memory
cgroup limit, allocations in kvm_s390_vcpu_setup() can fail. This causes
execution to jump to the out_ucontrol_uninit and out_free_sie_block error
paths.

While these error paths free vcpu->arch.sie_block and handle the child
gmap, it appears they miss calling kvm_s390_free_mmu_cache() to free
vcpu->arch.mc.

Could this result in a permanent memory leak of vcpu->arch.mc and its
topped-up pages when vCPU creation fails?

>  	free_page((unsigned long)(vcpu->arch.sie_block));
>  	return rc;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260803160924.236807-1-imbrenda@linux.ibm.com?part=19

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 23/23] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu()
  2026-08-03 16:09 ` [GIT PULL v1 23/23] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
@ 2026-08-03 17:19   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:19 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Alexander Gordeev, Heiko Carstens, kvm, linux-s390, Vasily Gorbik

> 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")
> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
> Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
> 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/20260803160924.236807-1-imbrenda@linux.ibm.com?part=23


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 22/23] KVM: s390: Fix ordering when adding to SCA
  2026-08-03 16:09 ` [GIT PULL v1 22/23] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
@ 2026-08-03 17:26   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:26 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: kvm, Vasily Gorbik, Alexander Gordeev, Heiko Carstens, linux-s390

> 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")
> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
> Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
> 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/20260803160924.236807-1-imbrenda@linux.ibm.com?part=22


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 21/23] KVM: s390: Return -EINTR if a signal is pending while faulting-in
  2026-08-03 16:09 ` [GIT PULL v1 21/23] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
@ 2026-08-03 17:40   ` sashiko-bot
  0 siblings, 0 replies; 47+ messages in thread
From: sashiko-bot @ 2026-08-03 17:40 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: Heiko Carstens, Alexander Gordeev, linux-s390, Vasily Gorbik, kvm

> 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.
> 
> Fixes: e907ae530133 ("KVM: s390: Add helper functions for fault handling")
> 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/20260803160924.236807-1-imbrenda@linux.ibm.com?part=21


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes
  2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
                   ` (22 preceding siblings ...)
  2026-08-03 16:09 ` [GIT PULL v1 23/23] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
@ 2026-08-06 13:48 ` Paolo Bonzini
  23 siblings, 0 replies; 47+ messages in thread
From: Paolo Bonzini @ 2026-08-06 13:48 UTC (permalink / raw)
  To: Claudio Imbrenda; +Cc: kvm, linux-s390, frankja, borntraeger

On Mon, Aug 3, 2026 at 6:09 PM Claudio Imbrenda <imbrenda@linux.ibm.com> wrote:
>
> Ciao Paolo,
>
> In this pull request there are a bunch of fixes to various KVM/s390 and
> vfio-ccw issues.
>
> There are still some small known bugs, which will be addressed later in
> a different series.
>
> The following changes since commit 9972befc3e34ff8b6847198c84f11bfc312dde40:
>
>   KVM: s390: Fall back to short-term pinning in MAP ioctl (2026-07-27 09:23:53 +0200)
>
> are available in the Git repository at:
>
>   https://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git tags/kvm-s390-master-7.2-3
>
> for you to fetch changes up to feadc5e84dcb53422a437556c35af9efd9826fd5:
>
>   KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() (2026-08-03 17:09:46 +0200)

Pulled, thanks.

Paolo

> ----------------------------------------------------------------
> KVM: s390: Misc fixes for 7.2
>
> 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.
>
> ----------------------------------------------------------------
> Claudio Imbrenda (13):
>       KVM: s390: Fix unlikely NULL gmap dereference
>       KVM: s390: Do not free SCA if it was not allocated
>       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()
>
> Eric Farman (10):
>       s390/vfio_ccw: Free all memory if cp_init() fails
>       s390/vfio_ccw: Limit the number of channel program segments
>       s390/vfio_ccw: Fix out of bounds check on CCW array
>       s390/vfio_ccw: Ensure first IDAW remains constant
>       s390/vfio_ccw: Calculate idal length based on idaw type
>       s390/vfio_ccw: Ensure index for read/write regions are within range
>       s390/vfio_ccw: Cancel existing workqueues
>       s390/vfio_ccw: Move cp cleanup out of not operational
>       s390/vfio_ccw: Selectively expand io_mutex
>       s390/vfio_ccw: Implement a crw lock
>
>  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            | 125 +++++++++++++++++++++++-------------
>  arch/s390/kvm/priv.c                |  10 +--
>  arch/s390/kvm/pv.c                  |  43 +++++++------
>  drivers/s390/cio/vfio_ccw_async.c   |  16 +++++
>  drivers/s390/cio/vfio_ccw_chp.c     |  31 +++++++--
>  drivers/s390/cio/vfio_ccw_cp.c      |  74 +++++++++++++++------
>  drivers/s390/cio/vfio_ccw_cp.h      |  10 +++
>  drivers/s390/cio/vfio_ccw_drv.c     |  21 +++++-
>  drivers/s390/cio/vfio_ccw_fsm.c     |   8 ++-
>  drivers/s390/cio/vfio_ccw_ops.c     |  39 +++++++++--
>  drivers/s390/cio/vfio_ccw_private.h |  10 ++-
>  16 files changed, 320 insertions(+), 118 deletions(-)
>


^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2026-08-06 13:48 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-03 16:09 [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Claudio Imbrenda
2026-08-03 16:09 ` [GIT PULL v1 01/23] s390/vfio_ccw: Free all memory if cp_init() fails Claudio Imbrenda
2026-08-03 16:28   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 02/23] s390/vfio_ccw: Limit the number of channel program segments Claudio Imbrenda
2026-08-03 16:32   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 03/23] s390/vfio_ccw: Fix out of bounds check on CCW array Claudio Imbrenda
2026-08-03 16:09 ` [GIT PULL v1 04/23] s390/vfio_ccw: Ensure first IDAW remains constant Claudio Imbrenda
2026-08-03 16:24   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 05/23] s390/vfio_ccw: Calculate idal length based on idaw type Claudio Imbrenda
2026-08-03 16:24   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 06/23] s390/vfio_ccw: Ensure index for read/write regions are within range Claudio Imbrenda
2026-08-03 16:34   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 07/23] s390/vfio_ccw: Cancel existing workqueues Claudio Imbrenda
2026-08-03 16:41   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 08/23] s390/vfio_ccw: Move cp cleanup out of not operational Claudio Imbrenda
2026-08-03 16:39   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 09/23] s390/vfio_ccw: Selectively expand io_mutex Claudio Imbrenda
2026-08-03 16:54   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 10/23] s390/vfio_ccw: Implement a crw lock Claudio Imbrenda
2026-08-03 16:51   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 11/23] KVM: s390: Fix unlikely NULL gmap dereference Claudio Imbrenda
2026-08-03 16:43   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 12/23] KVM: s390: Do not free SCA if it was not allocated Claudio Imbrenda
2026-08-03 16:49   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 13/23] KVM: s390: Fix kvm_s390_vcpu_unsetup_cmma() Claudio Imbrenda
2026-08-03 16:54   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 14/23] KVM: s390: Fix overclearing ESCA in case of error Claudio Imbrenda
2026-08-03 17:03   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 15/23] KVM: s390: ucontrol: Fix sca_clear_ext_call() Claudio Imbrenda
2026-08-03 17:09   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 16/23] KVM: s390: Fix leaking of PGM_ADDRESSING to userspace Claudio Imbrenda
2026-08-03 17:14   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 17/23] KVM: s390: Fix race in __do_essa() Claudio Imbrenda
2026-08-03 17:04   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 18/23] KVM: s390: cmma: Fix dirty tracking when removing memslot Claudio Imbrenda
2026-08-03 17:12   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 19/23] KVM: s390: ucontrol: Add missing locking around gmap_remove_child() Claudio Imbrenda
2026-08-03 17:19   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 20/23] KVM: s390: Free the mmu cache when kvm_arch_vcpu_create() fails Claudio Imbrenda
2026-08-03 17:13   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 21/23] KVM: s390: Return -EINTR if a signal is pending while faulting-in Claudio Imbrenda
2026-08-03 17:40   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 22/23] KVM: s390: Fix ordering when adding to SCA Claudio Imbrenda
2026-08-03 17:26   ` sashiko-bot
2026-08-03 16:09 ` [GIT PULL v1 23/23] KVM: s390: Fix cleanup in kvm_s390_pv_create_cpu() Claudio Imbrenda
2026-08-03 17:19   ` sashiko-bot
2026-08-06 13:48 ` [GIT PULL v1 00/23] KVM: s390: Misc KVM and vfio-ccw fixes Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox