[PATCH] scsi: zfcp: bound the RSCN page walk to the status read payload

From: Yehyeong Lee

Date: Thu Oct 22 2026 - 22:21:40 EST


zfcp_fc_incoming_rscn() takes the number of RSCN pages from rscn_plen in
the received ELS and walks that many four byte pages out of the status
read buffer payload. The fabric chooses rscn_plen, it is a 16 bit field,
and nothing compares it against the payload. A value of 65535 gives 16383
entries, so the loop reads up to 65532 bytes out of a payload of
FSF_STATUS_READ_PAYLOAD_SIZE, which is 4032. The status read buffer is a
single page and its payload ends at the page boundary, so the walk
continues into whatever follows that page.

Every iteration also hands the four bytes it just read to
zfcp_fc_enqueue_event(), and that event reaches user space through
fc_host_post_event(), so the bytes past the payload are reported and not
merely read.

libfc bounds the same field. fc_disc_recv_rscn_req() refuses an RSCN whose
rscn_plen is not covered by the received frame. zfcp does not share that
code, so add the equivalent test here. Compare against the payload size
rather than the firmware reported srb->length, because a bogus srb->length
need not reach the payload at all.

A conforming RSCN is unaffected. An FC data field holds at most 2112
bytes, so at most 528 pages, well under the 1008 the payload can hold.

This is an out of bounds read and an information leak to user space. It is
not a write and it corrupts no state. It assumes the adapter passes
rscn_plen through unchanged, the same assumption the host bus adapter
mediated paths in other drivers already make, and one the driver cannot
check for itself.

Not tested on hardware. The bound follows from the field widths and the
payload size.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
drivers/s390/scsi/zfcp_fc.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index 05d0812978798..24efd29b66bfc 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -270,6 +270,18 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req)
no_entries = be16_to_cpu(head->rscn_plen) /
sizeof(struct fc_els_rscn_page);

+ /*
+ * The fabric chooses rscn_plen, so refuse a value that would walk
+ * the page list past the end of the status read payload.
+ */
+ if (no_entries > FSF_STATUS_READ_PAYLOAD_SIZE /
+ sizeof(struct fc_els_rscn_page)) {
+ dev_warn(&adapter->ccw_device->dev,
+ "An RSCN with a payload length of %u was dropped\n",
+ be16_to_cpu(head->rscn_plen));
+ return;
+ }
+
if (no_entries > 1) {
/* handle failed ports */
unsigned long flags;

base-commit: f47d223627f80cb7a1eb14c585fe6cb35de5e984
--
2.43.0