fix(core): remove auxiliary casting in battery increment fetching.
What changed, and why it matters
This commit changes how a hardware wallet tracks battery wear. It removes a cast that was truncating a fractional cycle counter to a whole number, and adds interrupt locks around several battery-related operations. The practical effect is that small battery-cycle increments are no longer silently discarded, and concurrent access to shared battery data is better protected. There is no direct evidence in the commit that this fixes an exploitable security vulnerability; it appears to be a correctness and robustness fix.
Treat as a low-risk robustness/correctness fix. Review whether the interrupt locks fully cover all concurrent access paths to the battery driver state, and verify that the removed cast was not masking any intended integer-overflow behavior. No urgent security response is indicated by the diff alone.
Security signals we found
Removal of unsafe truncation cast that could cause loss of fractional battery cycle increments
Addition of interrupt locks (irq_lock/irq_unlock) around shared mutable battery state
Atomic read-and-reset of cycle_counter in bat_fetch_cycle_increment
No changelog entry and minimal commit message, reducing explicit security context
Evidence from the diff
In core/embed/io/power_manager/battery/battery.c, the patch: (1) replaces float cycle_increment = (float)((uint16_t)drv->cycle_counter); with float cycle_increment = drv->cycle_counter;, eliminating truncation of the fractional part; (2) resets drv->cycle_counter to 0.0f atomically under an interrupt lock; and (3) adds irq_lock()/irq_unlock() pairs around bat_fg_feed_sample(), bat_fg_initial_guess(), and bat_fg_update() to protect the shared sample_buf and cycle_counter state. The title mentions removing auxiliary casting in battery increment fetching, which matches the cycle counter change. The interrupt-lock additions suggest race-condition hardening, but the commit message does not frame it as a security fix.
Changed components
core/embed/io/power_manager/battery/battery.cBattery fuel gauge state (drv->fg_state, drv->sample_buf, drv->cycle_counter)Trezor Core power management subsystemInspect captured patch +20 / −1
diff --git a/core/embed/io/power_manager/battery/battery.c b/core/embed/io/power_manager/battery/battery.c
index be441fd88..768645896 100644
--- a/core/embed/io/power_manager/battery/battery.c
+++ b/core/embed/io/power_manager/battery/battery.c
@@ -21,6 +21,8 @@
#include <trezor_rtl.h>
+#include <sys/irq.h>
+
#include "battery.h"
#include "battery_model.h"
#include "fuel_gauge.h"
@@ -93,6 +95,8 @@ ts_t bat_fg_feed_sample(float voltage_V, float current_mA, float temp_C) {
return TS_ENOINIT;
}
+ irq_key_t key = irq_lock();
+
// Store battery data in the buffer
drv->sample_buf.samples[drv->sample_buf.head_idx].voltage_V = voltage_V;
drv->sample_buf.samples[drv->sample_buf.head_idx].current_mA = current_mA;
@@ -113,6 +117,8 @@ ts_t bat_fg_feed_sample(float voltage_V, float current_mA, float temp_C) {
}
}
+ irq_unlock(key);
+
return TS_OK;
}
@@ -128,6 +134,8 @@ ts_t bat_fg_initial_guess() {
return TS_EINVAL;
}
+ irq_key_t key = irq_lock();
+
// Calculate average voltage, current and temperature from the sampling
// buffer and run the fuel gauge initial guess
uint8_t buf_idx = drv->sample_buf.tail_idx;
@@ -155,6 +163,8 @@ ts_t bat_fg_initial_guess() {
fuel_gauge_initial_guess(&drv->fg_state, &drv->battery_model, vbat_avg,
ibat_avg, ntc_temp_avg);
+ irq_unlock(key);
+
drv->fg_locked = true;
return TS_OK;
@@ -199,6 +209,8 @@ ts_t bat_fg_update(uint32_t dt_ms, float voltage_V, float current_mA,
return TS_EINVAL;
}
+ irq_key_t key = irq_lock();
+
drv->cycle_counter += (fabsf(current_mA) * ((float)dt_ms / 3600000.0f)) /
(2 * battery_total_capacity(&drv->battery_model, 25.0f,
current_mA >= 0.0f));
@@ -206,6 +218,8 @@ ts_t bat_fg_update(uint32_t dt_ms, float voltage_V, float current_mA,
fuel_gauge_update(&drv->fg_state, &drv->battery_model, dt_ms, voltage_V,
current_mA, temp_C);
+ irq_unlock(key);
+
return TS_OK;
}
@@ -237,8 +251,13 @@ float bat_fetch_cycle_increment(void) {
return 0.0f;
}
- float cycle_increment = (float)((uint16_t)drv->cycle_counter);
+ irq_key_t key = irq_lock();
+
+ float cycle_increment = drv->cycle_counter;
drv->cycle_counter = 0.0f;
+
+ irq_unlock(key);
+
return cycle_increment;
}
Why this scored 32/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.