* [PATCH] spi: ch341: handle transfers without a TX or RX buffer
@ 2026-09-29 8:11 Weibin Liu
2026-09-29 14:40 ` Mark Brown
0 siblings, 1 reply; 2+ messages in thread
From: Weibin Liu @ 2026-09-29 8:11 UTC (permalink / raw)
To: broonie; +Cc: jth, linux-spi, linux-kernel, stable
ch341_transfer_one() unconditionally copies from trans->tx_buf into the
TX packet and hands trans->rx_buf to usb_bulk_msg() for the readback.
The SPI core allows half-duplex transfers where either of the buffers
is NULL, so a transfer without TX data crashes the kernel on the memcpy
and a transfer without RX data makes usb_bulk_msg() store the received
data at address 0.
Only copy TX data when the transfer carries a TX buffer and fall back
to the TX packet buffer as a scratch area for the readback when the
transfer has no RX buffer. The packet buffer is 32 bytes, which covers
the maximum readback length of 31 bytes, and it is not used by
anything else while the readback runs.
Fixes: 8846739f52af ("spi: add ch341a usb2spi driver")
Cc: stable@vger.kernel.org # 6.11+
Signed-off-by: Weibin Liu <liuwb@xiaopeng.com>
---
Reviewer notes:
- Both failure modes are reachable from unprivileged userspace through
spidev: SPI_IOC_MESSAGE accepts transfers with either of the buffers
set to NULL, and the driver passes them on as-is.
- The readback fallback reuses the 32-byte TX packet buffer, which
covers the maximum readback length of 31 bytes. It is only used by
ch341_transfer_one() and ch341_set_cs(), both of which run
synchronously from the SPI core's transfer handling, so nothing
touches the buffer while the readback is in flight.
- Pre-fix reproducer: open /dev/spidev0.0 and issue a single
SPI_IOC_MESSAGE transfer with tx_buf = NULL (memcpy from NULL in
ch341_transfer_one()) or with rx_buf = NULL (usb_bulk_msg() stores
the readback at address 0).
Functionally verified in QEMU on x86_64: a CH341a adapter was emulated
with gadgetfs + dummy_hcd (the emulated device echoes every SPI stream
packet's payload back on the bulk IN endpoint). With this patch
applied the probe completes, and tx-only, rx-only and full-duplex
transfers issued through spidev succeed, with the full-duplex readback
matching the sent payload, and without a splat. The emulator and the
test program are local test tooling and are not part of this
submission.
drivers/spi/spi-ch341.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c
index 6448a44a8..6c6eb4ac7 100644
--- a/drivers/spi/spi-ch341.c
+++ b/drivers/spi/spi-ch341.c
@@ -78,14 +78,21 @@ static int ch341_transfer_one(struct spi_controller *host,
ch341->tx_buf[0] = CH341A_CMD_SPI_STREAM;
- memcpy(ch341->tx_buf + 1, trans->tx_buf, len - 1);
+ if (trans->tx_buf)
+ memcpy(ch341->tx_buf + 1, trans->tx_buf, len - 1);
ret = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, len,
NULL, CH341_DEFAULT_TIMEOUT);
if (ret)
return ret;
- return usb_bulk_msg(ch341->udev, ch341->read_pipe, trans->rx_buf,
+ /*
+ * Half-duplex transfers can come without a RX buffer; the packet
+ * buffer is not used by anything else during the synchronous
+ * transfer, so reuse it as a scratch area for the readback.
+ */
+ return usb_bulk_msg(ch341->udev, ch341->read_pipe,
+ trans->rx_buf ? trans->rx_buf : ch341->tx_buf,
len - 1, NULL, CH341_DEFAULT_TIMEOUT);
}
base-commit: 72d3fcf802c45d00b300f25b848a93c3a2bd7c7e
prerequisite-patch-id: e48582f6ffe124b3806593af6e22b74682c8a83f
prerequisite-patch-id: 369f74b9a7ecde56141b13ec671f9200345a3bab
--
2.50.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] spi: ch341: handle transfers without a TX or RX buffer
2026-09-29 8:11 [PATCH] spi: ch341: handle transfers without a TX or RX buffer Weibin Liu
@ 2026-09-29 14:40 ` Mark Brown
0 siblings, 0 replies; 2+ messages in thread
From: Mark Brown @ 2026-09-29 14:40 UTC (permalink / raw)
To: Weibin Liu; +Cc: jth, linux-spi, linux-kernel, stable
[-- Attachment #1: Type: text/plain, Size: 1081 bytes --]
On Tue, Sep 29, 2026 at 04:11:52PM +0800, Weibin Liu wrote:
> ch341_transfer_one() unconditionally copies from trans->tx_buf into the
> TX packet and hands trans->rx_buf to usb_bulk_msg() for the readback.
>
> The SPI core allows half-duplex transfers where either of the buffers
> is NULL, so a transfer without TX data crashes the kernel on the memcpy
> and a transfer without RX data makes usb_bulk_msg() store the received
> data at address 0.
...
> Functionally verified in QEMU on x86_64: a CH341a adapter was emulated
> with gadgetfs + dummy_hcd (the emulated device echoes every SPI stream
> packet's payload back on the bulk IN endpoint). With this patch
> applied the probe completes, and tx-only, rx-only and full-duplex
> transfers issued through spidev succeed, with the full-duplex readback
> matching the sent payload, and without a splat. The emulator and the
> test program are local test tooling and are not part of this
> submission.
Are you sure the actual hardware supports half duplex and the fix isn't
to set _MUST_RX and _MUST_TX?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-29 14:40 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-29 8:11 [PATCH] spi: ch341: handle transfers without a TX or RX buffer Weibin Liu
2026-09-29 14:40 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®