This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 6cb6c459872 arch/xtensa/esp32: Fix buffer overflow in SPI poll exchange
6cb6c459872 is described below
commit 6cb6c45987253862035641896f87ad0ef52bd929
Author: Chip L. <[email protected]>
AuthorDate: Fri Feb 27 02:52:15 2026 +0800
arch/xtensa/esp32: Fix buffer overflow in SPI poll exchange
The esp32_spi_poll_exchange() function previously used a hardcoded
length of sizeof(uint32_t) (4 bytes) for memcpy() operations and
pointer increments, disregarding the actual remaining transfer_size.
When an SPI transaction involved a data length not aligned to 4 bytes
(such as a 1-byte payload commonly used in sub-GHz radio drivers),
the driver forced a 4-byte memory transfer. This caused out-of-bounds
reads and writes, leading to stack smashing and fatal CPU exceptions
(e.g., EXCCAUSE=0000).
This patch resolves the memory corruption vulnerability by:
1. Calculating a precise `chunk` size for each iteration, strictly
bounded by the remaining `transfer_size`.
2. Limiting the memcpy() operations and the subsequent pointer
increments (tp and rp) to this exact chunk size.
3. Zero-initializing the temporary TX register (w_wd) before copying
to clear padding and prevent reading uninitialized memory.
4. Adding a NULL check for the receive pointer (rp) prior to the
memcpy operation to prevent unintended memory writes.
Signed-off-by: Chip L. <[email protected]>
---
arch/xtensa/src/esp32/esp32_spi.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/arch/xtensa/src/esp32/esp32_spi.c
b/arch/xtensa/src/esp32/esp32_spi.c
index d8931fd7b84..c64ac2d7be1 100644
--- a/arch/xtensa/src/esp32/esp32_spi.c
+++ b/arch/xtensa/src/esp32/esp32_spi.c
@@ -1104,12 +1104,19 @@ static void esp32_spi_poll_exchange(struct
esp32_spi_priv_s *priv,
for (int i = 0 ; i < transfer_size; i += sizeof(uint32_t))
{
uint32_t w_wd = UINT32_MAX;
+ uint32_t chunk = transfer_size - i;
+
+ if (chunk > sizeof(uint32_t))
+ {
+ chunk = sizeof(uint32_t);
+ }
if (tp != NULL)
{
- memcpy(&w_wd, tp, sizeof(uint32_t));
+ w_wd = 0; /* Clear padding */
+ memcpy(&w_wd, tp, chunk);
- tp += sizeof(uintptr_t);
+ tp += chunk;
}
putreg32(w_wd, data_buf_reg);
@@ -1160,13 +1167,22 @@ static void esp32_spi_poll_exchange(struct
esp32_spi_priv_s *priv,
for (int i = 0 ; i < transfer_size; i += sizeof(uint32_t))
{
uint32_t r_wd = getreg32(data_buf_reg);
+ uint32_t chunk = transfer_size - i;
+
+ if (chunk > sizeof(uint32_t))
+ {
+ chunk = sizeof(uint32_t);
+ }
spiinfo("recv=0x%" PRIx32 " data_reg=0x%" PRIxPTR "\n",
r_wd, data_buf_reg);
- memcpy(rp, &r_wd, sizeof(uint32_t));
+ if (rp != NULL)
+ {
+ memcpy(rp, &r_wd, chunk);
- rp += sizeof(uintptr_t);
+ rp += chunk;
+ }
/* Update data_buf_reg to point to the next data buffer
* register.