fix(core): fine tune BLE behavior after unexpected events
What changed, and why it matters
This commit adjusts how a Trezor hardware wallet's Bluetooth subsystem behaves after unexpected resets or state changes in its wireless companion chip (nRF). It makes pairing restart automatically if it was interrupted, stops advertising when no bonded peers exist, and ends pairing cleanly when a connection is established. These are robustness fixes to Bluetooth state management rather than obvious security patches, though poor BLE state handling can in principle create attack windows.
Treat as a normal robustness improvement. Reviewers may optionally assess whether the automatic re-advertising after unexpected pairing end could extend the pairing window unexpectedly, but no immediate security action is indicated by the diff alone.
Security signals we found
Bluetooth state-machine hardening after unexpected nRF reset
Automatic restart of pairing/advertising after unexpected pairing termination
Prevention of lingering connectable mode when no bonded peers exist
No explicit security wording, CVE, or changelog entry
Evidence from the diff
The change is confined to core/embed/io/ble/stm32/ble.c. It adds three behaviors: (1) when a status message arrives while the driver requested pairing mode and a peer connects, it calls ble_pairing_end() before clearing pairing flags; (2) if pairing mode ends unexpectedly while pairing is still requested, it restarts advertising via ble_send_advertising_on(drv, false) instead of finalizing pairing; (3) if the peer bond list is empty and the requested mode is connectable, it switches the requested mode to OFF. These are state-machine hardening changes after ‘unexpected events’ such as an nRF reset.
Changed components
core/embed/io/ble/stm32/ble.cTrezor Safe hardware wallet Bluetooth LE driverInspect captured patch +16 / −2
diff --git a/core/embed/io/ble/stm32/ble.c b/core/embed/io/ble/stm32/ble.c
index 0c4b29c25..682214758 100644
--- a/core/embed/io/ble/stm32/ble.c
+++ b/core/embed/io/ble/stm32/ble.c
@@ -225,6 +225,10 @@ static void ble_process_rx_msg_status(const uint8_t *data, uint32_t len) {
tsqueue_enqueue(&drv->event_queue, (uint8_t *)&event, sizeof(event),
NULL);
+ if (drv->mode_requested == BLE_MODE_PAIRING) {
+ ble_pairing_end(drv);
+ }
+
drv->pairing_allowed = false;
drv->pairing_requested = false;
if (msg.peer_count > 0) {
@@ -274,8 +278,12 @@ static void ble_process_rx_msg_status(const uint8_t *data, uint32_t len) {
drv->peer_count = msg.peer_count;
if (prev_mode == BLE_MODE_PAIRING && drv->mode_current != BLE_MODE_PAIRING) {
- // pairing mode ended
- ble_pairing_end(drv);
+ if (drv->mode_requested == BLE_MODE_PAIRING) {
+ // unexpected pairing end - restart pairing
+ ble_send_advertising_on(drv, false);
+ } else {
+ ble_pairing_end(drv);
+ }
}
if (drv->mode_requested == BLE_MODE_KEEP_CONNECTION && !drv->connected) {
@@ -293,6 +301,12 @@ static void ble_process_rx_msg_status(const uint8_t *data, uint32_t len) {
}
}
+ // if there are no peers (i.e. after wiping the bonds), it makes no sense to
+ // stay in connectable mode as there is no one that can connect
+ if (msg.peer_count == 0 && drv->mode_requested == BLE_MODE_CONNECTABLE) {
+ drv->mode_requested = BLE_MODE_OFF;
+ }
+
drv->status_valid = true;
}
Why this scored 24/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.