[PATCH] i3c: master: cdns: Fix IBI FIFO buffer overflow
From: zhangjiao2
Date: Thu Oct 29 2026 - 03:20:43 EST
From: zhang jiao <zhangjiao2@xxxxxxxxxxxxxxxxxxxx>
The cdns_i3c_master_handle_ibi() function reads the IBI payload length
from the hardware register field IBIR_XFER_BYTES(ibir) (0-31 bytes) and
uses it directly as the FIFO read length into slot->data, which is a
buffer of size dev->ibi->max_payload_len.
The slot->len is clamped with min_t() to max_payload_len AFTER the
i3c_readl_fifo() call has already written the data. If the hardware
reports more bytes than max_payload_len, the FIFO read overflows the
heap buffer before the clamp takes effect.
This can be triggered by a malfunctioning or malicious I3C device on
the bus that sends an IBI payload larger than the agreed-upon
max_payload_len, leading to kernel heap corruption.
Fix this by checking nbytes against max_payload_len BEFORE reading the
FIFO. If the payload exceeds the buffer, recycle the slot and let the
existing out path drain the FIFO. This matches the approach already
used in dw-i3c-master.c and svc-i3c-master.c.
Signed-off-by: zhang jiao <zhangjiao2@xxxxxxxxxxxxxxxxxxxx>
---
drivers/i3c/master/i3c-master-cdns.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index 2d98c1ce9b12..b5ffea1e6a4c 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -1318,13 +1318,18 @@ static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
if (!slot)
goto out_unlock;
- buf = slot->data;
-
nbytes = IBIR_XFER_BYTES(ibir);
- i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes);
+ if (nbytes > dev->ibi->max_payload_len) {
+ dev_dbg_ratelimited(&master->base.dev,
+ "IBI payload %zu bytes exceeds max %u, dropping\n",
+ nbytes, dev->ibi->max_payload_len);
+ i3c_generic_ibi_recycle_slot(data->ibi_pool, slot);
+ goto out_unlock;
+ }
- slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
- dev->ibi->max_payload_len);
+ buf = slot->data;
+ i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes);
+ slot->len = nbytes;
i3c_master_queue_ibi(dev, slot);
data_consumed = true;
--
2.33.0