spi_bus_lock: TOCTOU race on lock->acquiring_dev in bg_exit_core causes NULL deref crash (IDFGH-17600)
Environment
- ESP-IDF: v5.3.2 (race also present in v5.5.3 and master, verified)
- Target: ESP32-S3
- Crash mode: Guru Meditation, LoadProhibited
- Reproducibility: probabilistic, ~one event per several minutes of heavy SPI activity
Bug
In components/esp_hw_support/spi_bus_lock.c::bg_exit_core(), the volatile pointer lock->acquiring_dev is read multiple times without caching:
if (lock->acquiring_dev) { // L547
if (status & DEV_BG_MASK(lock->acquiring_dev)) { // L548 — re-reads
...
} else {
resume_dev_in_isr(lock->acquiring_dev, do_yield); // L554 — re-reads again
ret = true;
}
}acquiring_dev is declared volatile, so each read goes to memory — but on multi-core ESP32-S3 the pointer can be cleared between L547 and L548 (or L554) by another concurrent SPI completion ISR. When that happens, DEV_BG_MASK(NULL) dereferences NULL->mask (offset 8) and resume_dev_in_isr(NULL, ...) dereferences NULL->semphr (offset 0).
Crash signatures observed
Guru Meditation Error: Core 0 panic'ed (LoadProhibited).
PC: bg_exit_core (spi_bus_lock.c:548) EXCVADDR: 0x00000008
spi_bus_lock_bg_exit (spi_bus_lock.c:778)
spi_intr (spi_master.c:1015)
_xt_lowint1
esp_pm_impl_waiti (pm_impl.c:1047)
esp_vApplicationIdleHook
prvIdleTaskIdentical signature observed at L554 (EXCVADDR=0x00000000) on a separate run.
Suggested fix
Cache the volatile pointer once at the top of the conditional:
spi_bus_lock_dev_t *dev = (spi_bus_lock_dev_t *)lock->acquiring_dev;
if (dev) {
if (status & DEV_BG_MASK(dev)) {
BUS_LOCK_DEBUG_EXECUTE_CHECK(lock->acq_dev_bg_active);
ret = false;
} else {
resume_dev_in_isr(dev, do_yield);
ret = true;
}
}Reproduction context
LoRa SX126x over SPI2 (RadioLib + EspHal, ~2 Hz TX/RX with frequent setFrequency calls), NimBLE GATT server, SDMMC, PM enabled with DFS. Crash always inside SPI ISR completion path while CPU is in waiti. No minimal reproducer — failure rate ~one per several minutes of mixed SPI/BLE activity. Happy to gather more diagnostics.
Source: espressif/esp-idf