fix(core): properly configure mpu in power management interrupts
What changed, and why it matters
This commit fixes how the hardware's memory protection unit (MPU) is set up inside two power-management interrupt handlers. Before the fix, these interrupt routines may have run with the wrong MPU configuration, which could allow them to access memory regions they shouldn't or, conversely, crash because a needed region was blocked. The patch now switches the MPU to a safe default mode at the start of each interrupt and restores the previous mode before returning.
Treat as a hardening fix. Review whether any other interrupt handlers in the codebase also lack explicit MPU reconfiguration. No immediate emergency response is indicated by the diff alone, but firmware updates should include this fix.
Security signals we found
MPU misconfiguration in interrupt context
Memory access policy violation possible during PMIC/wireless-charger IRQ handling
Fix is defensive hardening rather than a clear remote exploit path
Evidence from the diff
The change adds mpu_reconfig(MPU_MODE_DEFAULT) at entry and mpu_restore(…) before exit in the EXTI interrupt handlers for the npm1300 PMIC and stwlc38 wireless-charger drivers. It also adds IRQ_LOG_ENTER/EXIT markers. The bug being fixed is that these interrupt handlers could execute with whatever MPU context the interrupted code had left active, potentially violating the firmware’s memory-protection policy during I2C/power-management event processing.
Changed components
core/embed/sys/power_manager/npm1300/npm1300.ccore/embed/sys/power_manager/stwlc38/stwlc38.cInspect captured patch +16 / −0
diff --git a/core/embed/sys/power_manager/npm1300/npm1300.c b/core/embed/sys/power_manager/npm1300/npm1300.c
index f7d2f9e34..5e8c62f86 100644
--- a/core/embed/sys/power_manager/npm1300/npm1300.c
+++ b/core/embed/sys/power_manager/npm1300/npm1300.c
@@ -24,6 +24,7 @@
#include <io/i2c_bus.h>
#include <sys/irq.h>
+#include <sys/mpu.h>
#include <sys/pmic.h>
#include <sys/systimer.h>
@@ -983,17 +984,23 @@ static void npm1300_i2c_callback(void* context, i2c_packet_t* packet) {
}
void NPM1300_EXTI_INTERRUPT_HANDLER(void) {
+ IRQ_LOG_ENTER();
+ mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
npm1300_driver_t* drv = &g_npm1300_driver;
// Clear the EXTI line pending bit
__HAL_GPIO_EXTI_CLEAR_FLAG(NPM1300_INT_PIN);
if (!drv->initialized) {
+ mpu_restore(mpu_mode);
+ IRQ_LOG_EXIT();
return;
}
drv->clear_events_requested = true;
npm1300_fsm_continue(drv);
+ mpu_restore(mpu_mode);
+ IRQ_LOG_EXIT();
}
// npm1300 driver FSM continuation function that decides what to do next
diff --git a/core/embed/sys/power_manager/stwlc38/stwlc38.c b/core/embed/sys/power_manager/stwlc38/stwlc38.c
index 17506a23c..b2322d971 100644
--- a/core/embed/sys/power_manager/stwlc38/stwlc38.c
+++ b/core/embed/sys/power_manager/stwlc38/stwlc38.c
@@ -22,6 +22,7 @@
#include <io/i2c_bus.h>
#include <sys/irq.h>
+#include <sys/mpu.h>
#include <sys/systimer.h>
#include "stwlc38.h"
@@ -366,12 +367,17 @@ static void stwlc38_i2c_callback(void *context, i2c_packet_t *packet) {
}
void STWLC38_EXTI_INTERRUPT_HANDLER(void) {
+ IRQ_LOG_ENTER();
+ mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT);
+
stwlc38_driver_t *drv = &g_stwlc38_driver;
// Clear the EXTI line pending bit
__HAL_GPIO_EXTI_CLEAR_FLAG(STWLC38_INT_PIN);
if (!drv->initialized) {
+ mpu_restore(mpu_mode);
+ IRQ_LOG_EXIT();
return;
}
@@ -379,6 +385,9 @@ void STWLC38_EXTI_INTERRUPT_HANDLER(void) {
drv->report_readout_requested = true;
stwlc38_fsm_continue(drv);
}
+
+ mpu_restore(mpu_mode);
+ IRQ_LOG_EXIT();
}
static void stwlc38_fsm_continue(stwlc38_driver_t *drv) {
Why this scored 41/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.