sprd_adi_transfer_one() never looks at the transfer length: the read path dereferences t->rx_buf as one u32 and stores the result back, and the write path reads two consecutive u32 values from t->tx_buf. A transfer whose length does not exactly match what the controller touches is a bug in the caller: a short transfer reads or writes past the end of the buffer, and a long transfer is silently truncated. The SPI core does not enforce the expected length, so reject reads whose length is not exactly sizeof(u32) and writes whose length is not exactly 2 * sizeof(u32) with -EINVAL before touching the buffers. The only in-tree user, the SC27xx PMIC driver, is updated by the previous patch to advertise the byte length of an ADI register access. Tested in QEMU (aarch64 virt) against Linux 7.3-rc7, with the controller node added to the guest device tree. QEMU has no model of this hardware (the MMIO window is backed by RAM), so this only exercises the software path. Transfers submitted through spidev confirm the new checks: a 4-byte read and an 8-byte write are accepted, every other length from 1 to 16 is rejected with -EINVAL, and the SC27xx driver's transfers pass once it advertises the byte length. No Spreadtrum hardware was available. Fixes: 7e2903cb91df ("spi: Add ADI driver for Spreadtrum platform") Cc: stable@vger.kernel.org # 4.15+ Signed-off-by: Weibin Liu Reviewed-by: Guanglei Zhu --- drivers/spi/spi-sprd-adi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index a6baaf02b3c8..ecec1da3ca7a 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -339,10 +339,20 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, int ret; if (t->rx_buf) { + /* ADI reads consume exactly one u32: reg in, value out. */ + if (t->len != sizeof(u32)) { + dev_err(sadi->dev, "invalid read length %u\n", t->len); + return -EINVAL; + } reg = *(u32 *)t->rx_buf; ret = sprd_adi_read(sadi, reg, &val); *(u32 *)t->rx_buf = val; } else if (t->tx_buf) { + /* ADI writes consume exactly two u32: reg and value. */ + if (t->len != 2 * sizeof(u32)) { + dev_err(sadi->dev, "invalid write length %u\n", t->len); + return -EINVAL; + } u32 *p = (u32 *)t->tx_buf; reg = *p++; val = *p; -- 2.50.1