fix(core): fix kernel crash when ext app fault
What changed, and why it matters
This patch fixes a kernel crash that could occur when an external (untrusted) application running on the Trezor device faults. The crash happened because the kernel tried to read a return address from a memory region it was not allowed to access. The fix temporarily relaxes memory protection just long enough to safely read that address, then restores it. It is a stability/reliability fix in a security-sensitive component, but the commit itself does not claim it is exploitable for theft of funds or secrets.
Treat as a hardening/stability fix and include it in the next firmware release. Review whether other fault-handler paths read task memory without temporarily adjusting MPU permissions. No immediate end-user action is required beyond applying the update when available.
Security signals we found
Kernel crash during external-app fault handling
MPU access violation when reading faulting task's stack
Secure-world/kernel memory isolation interaction
Fault-handler robustness issue
Evidence from the diff
In core/embed/sys/task/stm32/systask.c, get_return_addr() validates that ret_addr points inside the task stack, but on TrustZone/MPU-based systems the kernel/secure monitor may not have read access to the whole stack region. Reading *ret_addr could therefore trigger a memory-protection fault and crash the kernel while handling an external-application fault. The patch saves the current MPU mode, temporarily disables the MPU (MPU_MODE_DISABLED), reads the return address, restores the MPU mode, and returns the value. This prevents a nested fault/crash during fault handling.
Changed components
core/embed/sys/task/stm32/systask.cTrezor Core kernel task/fault handlingMPU/memory protection subsystemInspect captured patch +8 / −1
diff --git a/core/embed/sys/task/stm32/systask.c b/core/embed/sys/task/stm32/systask.c
index a40627e2..2d935739 100644
--- a/core/embed/sys/task/stm32/systask.c
+++ b/core/embed/sys/task/stm32/systask.c
@@ -487,7 +487,14 @@ static uint32_t get_return_addr(bool secure, bool privileged, uint32_t sp) {
}
#endif
- return *ret_addr;
+ // We checked that ret_addr is valid, but kernel/secmon need not
+ // to have access to the entire memory region where the stack resides =>
+ // MPU temporarily to read the return address.
+ mpu_mode_t mode = mpu_reconfig(MPU_MODE_DISABLED);
+ uint32_t addr = *ret_addr;
+ mpu_restore(mode);
+
+ return addr;
}
// Terminate active task from fault/exception handler
Why this scored 57/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.