* [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(®->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;
as well as URLs for NNTP newsgroup(s).