[PATCH v3 2/2] spi: sprd-adi: enforce the exact transfer length

From: Weibin Liu

Date: Mon Oct 26 2026 - 11:39:50 EST


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. If the controller is exposed through spidev, a userspace
client can submit invalid transfers in a tight loop, so use
dev_err_ratelimited() for the driver's rejection messages.

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. A burst of 32 invalid reads and 32 invalid writes emits
only 10 messages at each new driver call site. 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@xxxxxxxxxxxxxxx # 4.15+
Signed-off-by: Weibin Liu <liuwb@xxxxxxxxxxxx>
Reviewed-by: Guanglei Zhu <zhugl3@xxxxxxxxxxxx>
---
Changes in v3:
- Rate-limit invalid-length errors as suggested by Sashiko's review.

drivers/spi/spi-sprd-adi.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c
index a6baaf02b3c8..32e445cea0d3 100644
--- a/drivers/spi/spi-sprd-adi.c
+++ b/drivers/spi/spi-sprd-adi.c
@@ -339,10 +339,24 @@ 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_ratelimited(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_ratelimited(sadi->dev,
+ "invalid write length %u\n",
+ t->len);
+ return -EINVAL;
+ }
u32 *p = (u32 *)t->tx_buf;
reg = *p++;
val = *p;
--
2.50.1