From 20701190e023216d0213a107a491402ce2cc501e Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 9 Jul 2026 16:29:05 +0200 Subject: [PATCH 1/3] s390x/sclp: prevent re-reading the sclp header We verify the sccb length and then allocate based on that length. The following access re-reads the sccb again. This can race against other vCPUs overwriting the length field. sclp_service_call_protected does not need a change as the ultravisor provides a consistent snapshot. Fixes: c1db53a5910f ("s390/sclp: read sccb from mem based on provided length") Cc: qemu-stable@nongnu.org Signed-off-by: Christian Borntraeger Reviewed-by: Matthew Rosato Reviewed-by: Eric Farman Reviewed-by: Collin Walling Message-ID: <20260709142906.197474-2-borntraeger@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/sclp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 2d2cde7803..3c8cb16488 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -329,7 +329,8 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) /* * we want to work on a private copy of the sccb, to prevent guests * from playing dirty tricks by modifying the memory content after - * the host has checked the values + * the host has checked the values. + * Reuse the previously fetched header */ work_sccb = g_malloc0(be16_to_cpu(header.length)); ret = address_space_read(as, sccb, attrs, @@ -337,6 +338,7 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) if (ret != MEMTX_OK) { return -PGM_ADDRESSING; } + work_sccb->h = header; if (!sclp_command_code_valid(code)) { work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); From 8a116a28535c34b001e68b52f85d6be3acb75350 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Thu, 9 Jul 2026 16:29:06 +0200 Subject: [PATCH 2/3] s390x/sclpcpi: check event length field before reading from buffer A guest might send a too short SCCB with SCLP_EVENT_CTRL_PGM_ID. QEMU would fill its data structures with garbage data. Check for the precise length of the CBI data structure and reject otherwise. Fixes: f345978f24be ("hw/s390x: add Control-Program Identification to QOM") Cc: qemu-stable@nongnu.org Signed-off-by: Christian Borntraeger Reviewed-by: Matthew Rosato Reviewed-by: Janosch Frank Reviewed-by: Eric Farman Message-ID: <20260709142906.197474-3-borntraeger@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/sclpcpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/s390x/sclpcpi.c b/hw/s390x/sclpcpi.c index 68fc1b809b..ec4bdf2350 100644 --- a/hw/s390x/sclpcpi.c +++ b/hw/s390x/sclpcpi.c @@ -97,6 +97,11 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) ebh); SCLPEventCPI *e = SCLP_EVENT_CPI(event); + /* Caller checks sccb length, buffer header checking is our duty */ + if (be16_to_cpu(evt_buf_hdr->length) != sizeof(ControlProgramIdMsg)) { + return SCLP_RC_INCONSISTENT_LENGTHS; + } + ascii_put(e->system_type, (char *)cpim->data.system_type, sizeof(cpim->data.system_type)); ascii_put(e->system_name, (char *)cpim->data.system_name, From 33bece0fa121c0a85df4f0372145ca74b967e78e Mon Sep 17 00:00:00 2001 From: Eric Farman Date: Mon, 13 Jul 2026 09:47:08 +0200 Subject: [PATCH 3/3] s390x/css: firm up handling of chained TIC CCWs The logic in css_interpret_ccw() correctly returns -EINVAL if a Transfer-In-Channel (TIC) CCW is command chained to another TIC CCW. The same routine also correctly returns -EINVAL if 256 CCWs do not perform a data transfer as part of the I/O operation [0]. What is missing, however, is a combination of these two, where a loop can be generated that will continue processing CCWs but without providing an opportunity to catch a breath. Fix this by capping the number of TIC CCWs in a channel program at the same limit as the CCWs without data transfer. [0] See "Invalid Sequence" in z/Architecture Principles of Operation (SA22-7832-14), p16-27 Cc: qemu-stable@nongnu.org Signed-off-by: Eric Farman Acked-by: Christian Borntraeger Reviewed-by: Farhan Ali Signed-off-by: Christian Borntraeger Message-ID: <20260713074708.884282-1-borntraeger@linux.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 7 +++++++ include/hw/s390x/css.h | 1 + 2 files changed, 8 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 29ba39f79e..3a67b67053 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1078,6 +1078,12 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, ret = -EINVAL; break; } + /* Limit the number of TICs in a given channel program */ + if (sch->ccw_tic_cnt == 255) { + ret = -EINVAL; + break; + } + sch->ccw_tic_cnt++; sch->channel_prog = ccw.cda; ret = -EAGAIN; break; @@ -1129,6 +1135,7 @@ static void sch_handle_start_func_virtual(SubchDev *sch) sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT); schib->scsw.flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0; sch->ccw_no_data_cnt = 0; + sch->ccw_tic_cnt = 0; suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND); } else { /* Start Function resumed via rsch */ diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index d3326237c9..79b41f305e 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -132,6 +132,7 @@ struct SubchDev { bool ccw_fmt_1; bool thinint_active; uint8_t ccw_no_data_cnt; + uint8_t ccw_tic_cnt; uint16_t migrated_schid; /* used for mismatch detection */ CcwDataStream cds; /* transport-provided data: */