Linux s390 Architecture development
 help / color / mirror / Atom feed
* [PATCH v7 0/5] s390/sclp: Misc fixes
@ 2026-09-23  7:40 Alexander Egorenkov
  2026-09-23  7:40 ` [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust Alexander Egorenkov
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Alexander Egorenkov @ 2026-09-23  7:40 UTC (permalink / raw)
  To: oberpar; +Cc: gor, hca, agordeev, borntraeger, linux390-list, linux-s390

This series consists of several fixes for the s390 SCLP driver.

* The first patch makes sclp_dispatch_evbufs() more safe while parsing event buffers
  contained in a received SCCB buffer.
* The second patch introduces the macro sclp_gds_for_each() to safely iterate over
  GDS {sub}vectors and serves to improve error handling in sclp_find_gds_{sub}vector()
  to prevent out-of-range memory read and potential infinite loops
  when a malformed event buffer is received from SCLP.
* The third patch reuses the macro sclp_gds_for_each() in SCLP TTY introduced in the first patch
  to replace manual and error-prone iteration over entries of a GDS {sub}vector to fix
  the same issues addressed in the first patch.
* The fourth patch fixes 2 potential illegal memory accesses when reading
  the value from a GDS subvector in SCLP event buffers sent by OCF.
* The fifth patch fixes race situations with in-flight callbacks and sclp_unregister() calls.

Changes since v6
----------------
- Rework the patch "s390/sclp: Make parsing of received event buffers more robust"
  - Move event buffer header checks into the parsing loop to make code more readable as suggested by Peter
  - Add check for SCCB buffer length as suggested by Peter
  - Return with -EINVAL from sclp_dispatch_evbufs() if SCCB or event buffer checks fail
  - Improved commit message

Changes since v5
----------------
- Added patch "s390/sclp: Make parsing of received event buffers more robust"
  - Reported by Sashiko
- Rework the patch "s390/sclp: Introduce macro sclp_gds_for_each()"
  - Explicit cast of start and end parameters to void* removing the need
    for the caller to use extra void* variables for start and end, and also
    protecting from mistakes when using non-void* variables when calculating n
- Rework the patch "s390/sclp_ocf: Fix computation of length of GDS values"
  - Improved commit description as suggested by Peter

Changes since v4
----------------
- Drop patch "s390/sclp: Drop volatile type class from SCLP state variables"
  - There are several doubts to it being correct in all situations
- Introduce the macro sclp_gds_for_each()
  - Reusable and safe iteration over GDS {sub}vectors
  - Make use of sclp_gds_for_each() in SCLP TTY
- Rework the patch "s390/sclp: Ensure no callback gets called after sclp_{un}register() returns"
  - Remove waiting for SCLP mask and reading states to become idle from sclp_register() on sclp_init_mask() failure
    - First, it is incorrect to sleep in sclp_register() which is called from atomic context
      - sclp_console_init() -> sclp_rw_init() -> sclp_register()
      - sclp_vt220_con_init() -> __sclp_vt220_init() -> sclp_register()
    - Second, it is redundant because no race situation can occur if sclp_init_mask() fails because
      in that case no events can be received from SCLP due to SCLP receive event mask update performed
      in sclp_init_mask() having failed
  - Add might_sleep() to sclp_unregister() to indicate that the function could potentially sleep
  - Adjust coding style of function sclp_unregister()
- Add "Fixes" tag where necessary

Changes since v3
----------------
- Rework the patch "s390/sclp: Ensure no callback gets called after sclp_{un}register() returns"
  - Shorten and reword the commit description
  - Replace wake_up_all_locked() with wake_up_all()
  - Replace sclp_init_state with sclp_mask_state in wait queue condition
  - Call wake_up_all() unconditionally
  - Add call to wake_up_call() in sclp_init_mask() after updating sclp_mask_state 

Changes since v2
----------------
- Add 2 new patches:
  - s390/sclp: Drop volatile type class from SCLP state variables
  - s390/sclp: Improve robustness of sclp_find_gds_{sub}vector()
- Rework the patch "s390/sclp: Ensure no callback gets called after sclp_unregister() returns"
  to implement Peter Oberparleiter's suggestion with a global wait queue and checking
  the state variables as its condition. It turns out the implementation with a single completion
  per struct sclp_register is inadequate because theoretically the callback state_change_fn() and receive_fn()
  could get invoked in parallel, however unlikely. Furthermore, the same race situation might happen
  with sclp_register() too. 

Changes since v1
----------------
- Drop redundant empty lines in sclp.c
- Make commit message more verbose for the fix in sclp.c

Alexander Egorenkov (5):
  s390/sclp: Make parsing of received event buffers more robust
  s390/sclp: Introduce macro sclp_gds_for_each()
  s390/sclp_tty: Make use of sclp_gds_for_each()
  s390/sclp_ocf: Fix computation of length of GDS values
  s390/sclp: Ensure no callback gets called after sclp_unregister()
    returns

 drivers/s390/char/sclp.c     | 42 +++++++++++++++++++++++++++---------
 drivers/s390/char/sclp.h     | 24 ++++++++++++++-------
 drivers/s390/char/sclp_ocf.c |  4 ++--
 drivers/s390/char/sclp_tty.c | 24 ++++++++-------------
 4 files changed, 59 insertions(+), 35 deletions(-)

-- 
2.53.0


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

* [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust
  2026-09-23  7:40 [PATCH v7 0/5] s390/sclp: Misc fixes Alexander Egorenkov
@ 2026-09-23  7:40 ` Alexander Egorenkov
  2026-09-23  7:52   ` sashiko-bot
  2026-09-23  7:40 ` [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each() Alexander Egorenkov
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Alexander Egorenkov @ 2026-09-23  7:40 UTC (permalink / raw)
  To: oberpar; +Cc: gor, hca, agordeev, borntraeger, linux390-list, linux-s390

Validate header fields of SCCB and event buffers to protect from potential
out-of-range memory accesses which might be caused by malformed hardware
responses.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
---
 drivers/s390/char/sclp.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 98e334724a62..5a4e4001dfa8 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -532,8 +532,7 @@ EXPORT_SYMBOL(sclp_add_request);
 
 /* Dispatch events found in request buffer to registered listeners. Return 0
  * if all events were dispatched, non-zero otherwise. */
-static int
-sclp_dispatch_evbufs(struct sccb_header *sccb)
+static int sclp_dispatch_evbufs(struct sccb_header *sccb)
 {
 	unsigned long flags;
 	struct evbuf_header *evbuf;
@@ -542,14 +541,25 @@ sclp_dispatch_evbufs(struct sccb_header *sccb)
 	int offset;
 	int rc;
 
+	/* Check for malformed hardware response */
+	if (sccb->length > PAGE_SIZE)
+		return -EINVAL;
+
 	spin_lock_irqsave(&sclp_lock, flags);
 	rc = 0;
 	for (offset = sizeof(struct sccb_header); offset < sccb->length;
 	     offset += evbuf->length) {
-		evbuf = (struct evbuf_header *) ((addr_t) sccb + offset);
 		/* Check for malformed hardware response */
-		if (evbuf->length == 0)
+		if (offset + sizeof(struct evbuf_header) > sccb->length) {
+			rc = -EINVAL;
 			break;
+		}
+		evbuf = (struct evbuf_header *) ((addr_t) sccb + offset);
+		if (evbuf->length < sizeof(*evbuf) ||
+		    offset + evbuf->length > sccb->length) {
+			rc = -EINVAL;
+			break;
+		}
 		/* Search for event handler */
 		reg = NULL;
 		list_for_each(l, &sclp_reg_list) {
-- 
2.53.0


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

* [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each()
  2026-09-23  7:40 [PATCH v7 0/5] s390/sclp: Misc fixes Alexander Egorenkov
  2026-09-23  7:40 ` [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust Alexander Egorenkov
@ 2026-09-23  7:40 ` Alexander Egorenkov
  2026-09-23  7:52   ` sashiko-bot
  2026-09-23 10:57   ` Christian Borntraeger
  2026-09-23  7:40 ` [PATCH v7 3/5] s390/sclp_tty: Make use of sclp_gds_for_each() Alexander Egorenkov
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 12+ messages in thread
From: Alexander Egorenkov @ 2026-09-23  7:40 UTC (permalink / raw)
  To: oberpar; +Cc: gor, hca, agordeev, borntraeger, linux390-list, linux-s390

sclp_find_gds_{sub}vector() does not deal well with malformed event buffers
consisting of GDS {sub}vectors. This can result in an infinite loop or
an out-of-bounds memory read. Therefore, abort with NULL if
* the next GDS header would exceed the given end boundary
* the length in a GDS header contains an invalid value.
  A valid length value in a GDS header should be at least as large
  as the size of the corresponding GDS header (2 or 4 bytes)
  but also not lead to exceeding the given end boundary.

Use the new macro in sclp_find_gds_{sub}vector() to iterate over entries
of a GDS {sub}vector in a safe manner bailing out on the first invalid
entry.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Fixes: 30c2df51173e ("[S390] sclp: event buffer dissection")
---
 drivers/s390/char/sclp.h | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index b31a680e0871..a006d7abfdf3 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -360,25 +360,33 @@ sclp_ascebc_str(char *str, int nr)
 	(machine_is_vm()) ? ASCEBC(str, nr) : ASCEBC_500(str, nr);
 }
 
-static inline struct gds_vector *
-sclp_find_gds_vector(void *start, void *end, u16 id)
+/* Loop over all GDS {sub}vectors in a safe manner. */
+#define sclp_gds_for_each(v, n, start, end)	\
+	for ((n) = (void*)(end) - (void*)(start), (v) = (typeof(v))(start);	\
+	     (n) >= sizeof(*(v)) && (v)->length >= sizeof(*(v)) && (v)->length <= (n);	\
+	     (n) -= (v)->length, (v) = (void*)(v) + (v)->length)
+
+static inline struct gds_vector *sclp_find_gds_vector(void *start,
+						      void *end, u16 id)
 {
 	struct gds_vector *v;
-
-	for (v = start; (void *) v < end; v = (void *) v + v->length)
+	int n;
+	sclp_gds_for_each(v, n, start, end) {
 		if (v->gds_id == id)
 			return v;
+	}
 	return NULL;
 }
 
-static inline struct gds_subvector *
-sclp_find_gds_subvector(void *start, void *end, u8 key)
+static inline struct gds_subvector *sclp_find_gds_subvector(void *start,
+							    void *end, u8 key)
 {
 	struct gds_subvector *sv;
-
-	for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length)
+	int n;
+	sclp_gds_for_each(sv, n, start, end) {
 		if (sv->key == key)
 			return sv;
+	}
 	return NULL;
 }
 
-- 
2.53.0


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

* [PATCH v7 3/5] s390/sclp_tty: Make use of sclp_gds_for_each()
  2026-09-23  7:40 [PATCH v7 0/5] s390/sclp: Misc fixes Alexander Egorenkov
  2026-09-23  7:40 ` [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust Alexander Egorenkov
  2026-09-23  7:40 ` [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each() Alexander Egorenkov
@ 2026-09-23  7:40 ` Alexander Egorenkov
  2026-09-23  7:52   ` sashiko-bot
  2026-09-23  7:40 ` [PATCH v7 4/5] s390/sclp_ocf: Fix computation of length of GDS values Alexander Egorenkov
  2026-09-23  7:40 ` [PATCH v7 5/5] s390/sclp: Ensure no callback gets called after sclp_unregister() returns Alexander Egorenkov
  4 siblings, 1 reply; 12+ messages in thread
From: Alexander Egorenkov @ 2026-09-23  7:40 UTC (permalink / raw)
  To: oberpar; +Cc: gor, hca, agordeev, borntraeger, linux390-list, linux-s390

Replace manual and error-prone iteration over entries of a GDS {sub}vector
with sclp_gds_for_each() which deals with erroneous entries in GDS
{sub}vectors more safely.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Fixes: 30c2df51173e ("[S390] sclp: event buffer dissection")
---
 drivers/s390/char/sclp_tty.c | 24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 0a92d08830e7..95ab3b090081 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -418,38 +418,32 @@ static void sclp_get_input(struct gds_subvector *sv)
 
 static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv)
 {
-	void *end;
-
-	end = (void *) sv + sv->length;
-	for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length)
+	int n;
+	sclp_gds_for_each(sv, n, sv + 1, (void *)sv + sv->length) {
 		if (sv->key == 0x30)
 			sclp_get_input(sv);
+	}
 }
 
 static inline void sclp_eval_textcmd(struct gds_vector *v)
 {
 	struct gds_subvector *sv;
-	void *end;
-
-	end = (void *) v + v->length;
-	for (sv = (struct gds_subvector *) (v + 1);
-	     (void *) sv < end; sv = (void *) sv + sv->length)
+	int n;
+	sclp_gds_for_each(sv, n, v + 1, (void *)v + v->length) {
 		if (sv->key == GDS_KEY_SELFDEFTEXTMSG)
 			sclp_eval_selfdeftextmsg(sv);
-
+	}
 }
 
 static inline void sclp_eval_cpmsu(struct gds_vector *v)
 {
-	void *end;
-
-	end = (void *) v + v->length;
-	for (v = v + 1; (void *) v < end; v = (void *) v + v->length)
+	int n;
+	sclp_gds_for_each(v, n, v + 1, (void *)v + v->length) {
 		if (v->gds_id == GDS_ID_TEXTCMD)
 			sclp_eval_textcmd(v);
+	}
 }
 
-
 static inline void sclp_eval_mdsmu(struct gds_vector *v)
 {
 	v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU);
-- 
2.53.0


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

* [PATCH v7 4/5] s390/sclp_ocf: Fix computation of length of GDS values
  2026-09-23  7:40 [PATCH v7 0/5] s390/sclp: Misc fixes Alexander Egorenkov
                   ` (2 preceding siblings ...)
  2026-09-23  7:40 ` [PATCH v7 3/5] s390/sclp_tty: Make use of sclp_gds_for_each() Alexander Egorenkov
@ 2026-09-23  7:40 ` Alexander Egorenkov
  2026-09-23  7:49   ` sashiko-bot
  2026-09-23  7:40 ` [PATCH v7 5/5] s390/sclp: Ensure no callback gets called after sclp_unregister() returns Alexander Egorenkov
  4 siblings, 1 reply; 12+ messages in thread
From: Alexander Egorenkov @ 2026-09-23  7:40 UTC (permalink / raw)
  To: oberpar; +Cc: gor, hca, agordeev, borntraeger, linux390-list, linux-s390

Fix length calculation for HMC-network and CPC names in OCF event data
by excluding the GDS subvector header size. This prevents a potential
invalid read access beyond the available GDS name data.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Fixes: 7eb9d5bec552 ("[S390] get CPC image name")
---
 drivers/s390/char/sclp_ocf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c
index 35f3a4a08b12..cee4bfa4a48a 100644
--- a/drivers/s390/char/sclp_ocf.c
+++ b/drivers/s390/char/sclp_ocf.c
@@ -66,13 +66,13 @@ static void sclp_ocf_handler(struct evbuf_header *evbuf)
 	/* Copy network name and cpc name. */
 	spin_lock(&sclp_ocf_lock);
 	if (netid) {
-		size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length);
+		size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length - sizeof(*netid));
 		memcpy(hmc_network, netid + 1, size);
 		EBCASC(hmc_network, size);
 		hmc_network[size] = 0;
 	}
 	if (cpc) {
-		size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
+		size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length - sizeof(*cpc));
 		memset(cpc_name, 0, OCF_LENGTH_CPC_NAME);
 		memcpy(cpc_name, cpc + 1, size);
 	}
-- 
2.53.0


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

* [PATCH v7 5/5] s390/sclp: Ensure no callback gets called after sclp_unregister() returns
  2026-09-23  7:40 [PATCH v7 0/5] s390/sclp: Misc fixes Alexander Egorenkov
                   ` (3 preceding siblings ...)
  2026-09-23  7:40 ` [PATCH v7 4/5] s390/sclp_ocf: Fix computation of length of GDS values Alexander Egorenkov
@ 2026-09-23  7:40 ` Alexander Egorenkov
  2026-09-23  7:51   ` sashiko-bot
  4 siblings, 1 reply; 12+ messages in thread
From: Alexander Egorenkov @ 2026-09-23  7:40 UTC (permalink / raw)
  To: oberpar; +Cc: gor, hca, agordeev, borntraeger, linux390-list, linux-s390

There is a potential race condition between sclp_unregister()
and sclp_dispatch_evbufs()/sclp_dispatch_state_change(). As a result,
it is not guaranteed that the callbacks registered with sclp_register()
will not get called one more time (and no more than one) after
sclp_unregister() returns.

The basic idea is to use a single global wait queue which is woken up
when no SCLP WRITE_EVENT_MASK and no SCLP READ_EVENT_DATA request is
outstanding. If both are true then it is guaranteed that no sclp_register
callback could be in-flight. Once the struct sclp_register given to
sclp_unregister() is removed from the list sclp_reg_list, no further
callbacks can be scheduled for the given struct sclp_register and it only
remains to wait until the SCLP driver becomes idle.

With this change sclp_unregister() may no longer be invoked from atomic
context or registered callbacks. But this represents no problem because
this is no regular use case and no driver using sclp_unregister() requires
this at the moment and likely should not require it in the future.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
---
 drivers/s390/char/sclp.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 5a4e4001dfa8..55b928a68593 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -20,6 +20,7 @@
 #include <linux/jiffies.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/wait.h>
 #include <asm/types.h>
 #include <asm/irq.h>
 #include <asm/debug.h>
@@ -67,6 +68,8 @@ static struct sclp_req sclp_init_req;
 static void *sclp_read_sccb;
 static struct init_sccb *sclp_init_sccb;
 
+static DECLARE_WAIT_QUEUE_HEAD(sclp_state_wq);
+
 /* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
 int sclp_console_pages = SCLP_CONSOLE_PAGES;
 /* Flag to indicate if buffer pages are dropped on buffer full condition */
@@ -598,6 +601,7 @@ sclp_read_cb(struct sclp_req *req, void *data)
 		sclp_dispatch_evbufs(sccb);
 	spin_lock_irqsave(&sclp_lock, flags);
 	sclp_reading_state = sclp_reading_state_idle;
+	wake_up_all(&sclp_state_wq);
 	spin_unlock_irqrestore(&sclp_lock, flags);
 }
 
@@ -908,19 +912,26 @@ sclp_register(struct sclp_register *reg)
 
 EXPORT_SYMBOL(sclp_register);
 
-/* Unregister event listener. */
-void
-sclp_unregister(struct sclp_register *reg)
+/* Unregister event listener.
+ * This function may sleep. Do not call it from atomic context or
+ * sclp_register.receive_fn(). */
+void sclp_unregister(struct sclp_register *reg)
 {
-	unsigned long flags;
+	might_sleep();
 
 	/* UREG: Event listener unregistered (b=caller) */
 	sclp_trace_register(2, "UREG", 0, _RET_IP_, reg);
 
-	spin_lock_irqsave(&sclp_lock, flags);
+	spin_lock_irq(&sclp_lock);
 	list_del(&reg->list);
-	spin_unlock_irqrestore(&sclp_lock, flags);
+	spin_unlock_irq(&sclp_lock);
 	sclp_init_mask(1);
+	spin_lock_irq(&sclp_lock);
+	wait_event_lock_irq(sclp_state_wq,
+			    (sclp_mask_state == sclp_mask_state_idle) &&
+			    (sclp_reading_state == sclp_reading_state_idle),
+			    sclp_lock);
+	spin_unlock_irq(&sclp_lock);
 }
 
 EXPORT_SYMBOL(sclp_unregister);
@@ -1046,6 +1057,7 @@ sclp_init_mask(int calculate)
 		}
 	}
 	sclp_mask_state = sclp_mask_state_idle;
+	wake_up_all(&sclp_state_wq);
 	spin_unlock_irqrestore(&sclp_lock, flags);
 	return rc;
 }
-- 
2.53.0


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

* Re: [PATCH v7 4/5] s390/sclp_ocf: Fix computation of length of GDS values
  2026-09-23  7:40 ` [PATCH v7 4/5] s390/sclp_ocf: Fix computation of length of GDS values Alexander Egorenkov
@ 2026-09-23  7:49   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-23  7:49 UTC (permalink / raw)
  To: Alexander Egorenkov
  Cc: Vasily Gorbik, linux-s390, Heiko Carstens, Christian Borntraeger,
	Alexander Gordeev

> Fix length calculation for HMC-network and CPC names in OCF event data
> by excluding the GDS subvector header size. This prevents a potential
> invalid read access beyond the available GDS name data.
> 
> Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>

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

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


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

* Re: [PATCH v7 5/5] s390/sclp: Ensure no callback gets called after sclp_unregister() returns
  2026-09-23  7:40 ` [PATCH v7 5/5] s390/sclp: Ensure no callback gets called after sclp_unregister() returns Alexander Egorenkov
@ 2026-09-23  7:51   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-23  7:51 UTC (permalink / raw)
  To: Alexander Egorenkov
  Cc: Heiko Carstens, linux-s390, Vasily Gorbik, Christian Borntraeger,
	Alexander Gordeev

> There is a potential race condition between sclp_unregister()
> and sclp_dispatch_evbufs()/sclp_dispatch_state_change(). As a result,
> it is not guaranteed that the callbacks registered with sclp_register()
> will not get called one more time (and no more than one) after
> sclp_unregister() returns.
> 
> The basic idea is to use a single global wait queue which is woken up
> when no SCLP WRITE_EVENT_MASK and no SCLP READ_EVENT_DATA request is
> outstanding. If both are true then it is guaranteed that no sclp_register
> callback could be in-flight. Once the struct sclp_register given to
> sclp_unregister() is removed from the list sclp_reg_list, no further
> callbacks can be scheduled for the given struct sclp_register and it only
> remains to wait until the SCLP driver becomes idle.
> 
> With this change sclp_unregister() may no longer be invoked from atomic
> context or registered callbacks. But this represents no problem because
> this is no regular use case and no driver using sclp_unregister() requires
> this at the moment and likely should not require it in the future.
> 
> Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>

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

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


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

* Re: [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each()
  2026-09-23  7:40 ` [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each() Alexander Egorenkov
@ 2026-09-23  7:52   ` sashiko-bot
  2026-09-23 10:57   ` Christian Borntraeger
  1 sibling, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-23  7:52 UTC (permalink / raw)
  To: Alexander Egorenkov
  Cc: Christian Borntraeger, Vasily Gorbik, linux-s390,
	Alexander Gordeev, Heiko Carstens

> sclp_find_gds_{sub}vector() does not deal well with malformed event buffers
> consisting of GDS {sub}vectors. This can result in an infinite loop or
> an out-of-bounds memory read. Therefore, abort with NULL if
> * the next GDS header would exceed the given end boundary
> * the length in a GDS header contains an invalid value.
>   A valid length value in a GDS header should be at least as large
>   as the size of the corresponding GDS header (2 or 4 bytes)
>   but also not lead to exceeding the given end boundary.
> 
> Use the new macro in sclp_find_gds_{sub}vector() to iterate over entries
> of a GDS {sub}vector in a safe manner bailing out on the first invalid
> entry.
> 
> Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>

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

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


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

* Re: [PATCH v7 3/5] s390/sclp_tty: Make use of sclp_gds_for_each()
  2026-09-23  7:40 ` [PATCH v7 3/5] s390/sclp_tty: Make use of sclp_gds_for_each() Alexander Egorenkov
@ 2026-09-23  7:52   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-23  7:52 UTC (permalink / raw)
  To: Alexander Egorenkov
  Cc: Heiko Carstens, linux-s390, Alexander Gordeev, Vasily Gorbik,
	Christian Borntraeger

> Replace manual and error-prone iteration over entries of a GDS {sub}vector
> with sclp_gds_for_each() which deals with erroneous entries in GDS
> {sub}vectors more safely.
> 
> Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>

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

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


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

* Re: [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust
  2026-09-23  7:40 ` [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust Alexander Egorenkov
@ 2026-09-23  7:52   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-23  7:52 UTC (permalink / raw)
  To: Alexander Egorenkov
  Cc: Alexander Gordeev, Christian Borntraeger, Heiko Carstens,
	linux-s390, Vasily Gorbik

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] s390/sclp: TOCTOU double fetch of sccb->length and evbuf->length
--

commit d21cb539ad66b7cd19d44f1b8944ce8a000b730d
Author: Alexander Egorenkov <egorenar@linux.ibm.com>

s390/sclp: Make parsing of received event buffers more robust

Validate header fields of SCCB and event buffers to protect from potential
out-of-range memory accesses which might be caused by malformed hardware
responses.

> diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
> index 98e334724a627..5a4e4001dfa8d 100644
> --- a/drivers/s390/char/sclp.c
> +++ b/drivers/s390/char/sclp.c
> @@ -532,8 +532,7 @@ EXPORT_SYMBOL(sclp_add_request);
>  
>  /* Dispatch events found in request buffer to registered listeners. Return 0
>   * if all events were dispatched, non-zero otherwise. */
> -static int
> -sclp_dispatch_evbufs(struct sccb_header *sccb)
> +static int sclp_dispatch_evbufs(struct sccb_header *sccb)
>  {
>  	unsigned long flags;
>  	struct evbuf_header *evbuf;
> @@ -542,14 +541,25 @@ sclp_dispatch_evbufs(struct sccb_header *sccb)
>  	int offset;
>  	int rc;
>  
> +	/* Check for malformed hardware response */
> +	if (sccb->length > PAGE_SIZE)
> +		return -EINVAL;
> +

[Severity: High]
In drivers/s390/char/sclp.c:sclp_dispatch_evbufs(), is it possible for a
malicious hypervisor to mutate sccb->length after this initial validation?

Since sccb points to DMA shared memory, this validation is performed outside
the sclp_lock.

>  	spin_lock_irqsave(&sclp_lock, flags);
>  	rc = 0;
>  	for (offset = sizeof(struct sccb_header); offset < sccb->length;
>  	     offset += evbuf->length) {

[Severity: High]
Does spin_lock_irqsave() act as a full compiler barrier here, forcing
sccb->length and evbuf->length to be re-fetched from shared memory on each loop
iteration?

If a malicious hypervisor mutates the lengths (e.g., setting sccb->length >
PAGE_SIZE or evbuf->length = 0) between the initial bounds checks and these
re-fetches, could it bypass the mitigation and cause out-of-bounds memory
reads or infinite loops?

> -		evbuf = (struct evbuf_header *) ((addr_t) sccb + offset);
>  		/* Check for malformed hardware response */
> -		if (evbuf->length == 0)
> +		if (offset + sizeof(struct evbuf_header) > sccb->length) {
> +			rc = -EINVAL;
>  			break;
> +		}
> +		evbuf = (struct evbuf_header *) ((addr_t) sccb + offset);
> +		if (evbuf->length < sizeof(*evbuf) ||
> +		    offset + evbuf->length > sccb->length) {

[Severity: High]
Do subsequent re-fetches of sccb->length and evbuf->length in these bounds
checks continue to expose a double-fetch TOCTOU window?

Because memory barriers like function calls or locking/unlocking occur during
the rest of the loop, the compiler may be forced to repeatedly fetch these
values from untrusted shared memory.

> +			rc = -EINVAL;
> +			break;
> +		}

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

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

* Re: [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each()
  2026-09-23  7:40 ` [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each() Alexander Egorenkov
  2026-09-23  7:52   ` sashiko-bot
@ 2026-09-23 10:57   ` Christian Borntraeger
  1 sibling, 0 replies; 12+ messages in thread
From: Christian Borntraeger @ 2026-09-23 10:57 UTC (permalink / raw)
  To: Alexander Egorenkov, oberpar
  Cc: gor, hca, agordeev, linux390-list, linux-s390



Am 23.09.26 um 09:40 schrieb Alexander Egorenkov:
> sclp_find_gds_{sub}vector() does not deal well with malformed event buffers
> consisting of GDS {sub}vectors. This can result in an infinite loop or
> an out-of-bounds memory read. Therefore, abort with NULL if
> * the next GDS header would exceed the given end boundary
> * the length in a GDS header contains an invalid value.
>    A valid length value in a GDS header should be at least as large
>    as the size of the corresponding GDS header (2 or 4 bytes)
>    but also not lead to exceeding the given end boundary.
> 
> Use the new macro in sclp_find_gds_{sub}vector() to iterate over entries
> of a GDS {sub}vector in a safe manner bailing out on the first invalid
> entry.
> 
> Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
> Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
> Fixes: 30c2df51173e ("[S390] sclp: event buffer dissection")
> ---
>   drivers/s390/char/sclp.h | 24 ++++++++++++++++--------
>   1 file changed, 16 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
> index b31a680e0871..a006d7abfdf3 100644
> --- a/drivers/s390/char/sclp.h
> +++ b/drivers/s390/char/sclp.h
> @@ -360,25 +360,33 @@ sclp_ascebc_str(char *str, int nr)
>   	(machine_is_vm()) ? ASCEBC(str, nr) : ASCEBC_500(str, nr);
>   }
>   
> -static inline struct gds_vector *
> -sclp_find_gds_vector(void *start, void *end, u16 id)
> +/* Loop over all GDS {sub}vectors in a safe manner. */
> +#define sclp_gds_for_each(v, n, start, end)	\
> +	for ((n) = (void*)(end) - (void*)(start), (v) = (typeof(v))(start);	\
> +	     (n) >= sizeof(*(v)) && (v)->length >= sizeof(*(v)) && (v)->length <= (n);	\
> +	     (n) -= (v)->length, (v) = (void*)(v) + (v)->length)

void * instead of void* for checkpatch

> +
> +static inline struct gds_vector *sclp_find_gds_vector(void *start,
> +						      void *end, u16 id)
>   {
>   	struct gds_vector *v;
> -
> -	for (v = start; (void *) v < end; v = (void *) v + v->length)
> +	int n;

add a blank line here and below? checkpatch complains. Same for the next patch.


> +	sclp_gds_for_each(v, n, start, end) {
>   		if (v->gds_id == id)
>   			return v;
> +	}
>   	return NULL;
>   }
>   
> -static inline struct gds_subvector *
> -sclp_find_gds_subvector(void *start, void *end, u8 key)
> +static inline struct gds_subvector *sclp_find_gds_subvector(void *start,
> +							    void *end, u8 key)
>   {
>   	struct gds_subvector *sv;
> -
> -	for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length)
> +	int n;
> +	sclp_gds_for_each(sv, n, start, end) {
>   		if (sv->key == key)
>   			return sv;
> +	}
>   	return NULL;
>   }
>   


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

end of thread, other threads:[~2026-09-23 10:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23  7:40 [PATCH v7 0/5] s390/sclp: Misc fixes Alexander Egorenkov
2026-09-23  7:40 ` [PATCH v7 1/5] s390/sclp: Make parsing of received event buffers more robust Alexander Egorenkov
2026-09-23  7:52   ` sashiko-bot
2026-09-23  7:40 ` [PATCH v7 2/5] s390/sclp: Introduce macro sclp_gds_for_each() Alexander Egorenkov
2026-09-23  7:52   ` sashiko-bot
2026-09-23 10:57   ` Christian Borntraeger
2026-09-23  7:40 ` [PATCH v7 3/5] s390/sclp_tty: Make use of sclp_gds_for_each() Alexander Egorenkov
2026-09-23  7:52   ` sashiko-bot
2026-09-23  7:40 ` [PATCH v7 4/5] s390/sclp_ocf: Fix computation of length of GDS values Alexander Egorenkov
2026-09-23  7:49   ` sashiko-bot
2026-09-23  7:40 ` [PATCH v7 5/5] s390/sclp: Ensure no callback gets called after sclp_unregister() returns Alexander Egorenkov
2026-09-23  7:51   ` sashiko-bot

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