feat(core): respect BLE settings in bootloader
What changed, and why it matters
This commit changes the Trezor bootloader so that Bluetooth Low Energy (BLE) settings are remembered across reboots. Previously, the bootloader would turn BLE back on even if the user had turned it off. Now the bootloader reads a saved 'BLE enabled' flag from backup memory and only enables BLE if the user had left it on. The pairing/setup workflows still force BLE on because they need it. This is a privacy/usability fix rather than a critical security patch, but it prevents an unwanted BLE radio from being active when the user expects it to be off.
Treat as a low-risk privacy/usability fix. No urgent action required for users, but ensure firmware update includes this change so user BLE preferences are honored in bootloader. Review whether other bootloader workflows that use BLE also explicitly enable it as needed.
Security signals we found
Fixes a state-persistence bug where a user-configured disable setting was ignored in bootloader context
Adds backup RAM storage for BLE enabled state with versioned struct
Uses BACKUP_RAM_ITEM_PROTECTED so the setting is erased on device wipe
Explicitly enables BLE only in workflows that require it (pairing/setup)
Changelog describes this as a fix for BLE on/off behavior in bootloader
Evidence from the diff
The patch adds a new BACKUP_RAM_KEY_BLE_SETTINGS key in backup RAM and a small ble_recovery_data_t struct (version + enabled flag). On ble_init(), the driver now reads this key and sets drv->enabled accordingly instead of unconditionally enabling BLE. On ble_set_enabled(), it writes the current enabled state to protected backup RAM so the setting persists across reboots. The bootloader BLE pairing and wireless setup workflows explicitly call ble_set_enabled(true) because they require BLE to function. The changelog fragment labels this as fixing issue 5952 for the T3W1 device.
Changed components
core/embed/io/ble/stm32/ble.ccore/embed/sys/backup_ram/inc/sys/backup_ram.hcore/embed/projects/bootloader/workflow/wf_ble_pairing_request.cTrezor Safe 3 / T3W1 bootloader BLE initializationInspect captured patch +31 / −4
diff --git a/core/embed/io/ble/stm32/ble.c b/core/embed/io/ble/stm32/ble.c
index cbab519f..4441dadb 100644
--- a/core/embed/io/ble/stm32/ble.c
+++ b/core/embed/io/ble/stm32/ble.c
@@ -27,6 +27,7 @@
#include <io/ble.h>
#include <io/nrf.h>
+#include <sys/backup_ram.h>
#include <sys/irq.h>
#include <sys/sysevent_source.h>
#include <sys/systick.h>
@@ -51,6 +52,11 @@
#define BLE_DATA_HEADER_SIZE 7
#define BLE_DATA_SIZE (BLE_RX_PACKET_SIZE + BLE_DATA_HEADER_SIZE)
+typedef struct {
+ uint8_t version;
+ bool enabled;
+} ble_recovery_data_t;
+
typedef struct {
ble_mode_t mode_requested;
ble_mode_t mode_current;
@@ -659,8 +665,16 @@ bool ble_init(void) {
goto cleanup;
}
- drv->power_level = BLE_TX_POWER_PLUS_4_DBM;
drv->enabled = true;
+ ble_recovery_data_t backup_data;
+ if (backup_ram_read(BACKUP_RAM_KEY_BLE_SETTINGS, &backup_data,
+ sizeof(backup_data), NULL)) {
+ if (backup_data.version == 1) {
+ drv->enabled = backup_data.enabled;
+ }
+ }
+
+ drv->power_level = BLE_TX_POWER_PLUS_4_DBM;
drv->initialized = true;
return true;
@@ -1357,6 +1371,11 @@ void ble_set_enabled(bool enabled) {
}
drv->enabled = enabled;
+
+ ble_recovery_data_t data = {.version = 1, .enabled = enabled};
+
+ backup_ram_write(BACKUP_RAM_KEY_BLE_SETTINGS, BACKUP_RAM_ITEM_PROTECTED,
+ &data, sizeof(data));
}
bool ble_get_enabled(void) {
diff --git a/core/embed/projects/bootloader/.changelog.d/5952.fixed b/core/embed/projects/bootloader/.changelog.d/5952.fixed
new file mode 100644
index 00000000..fa22c321
--- /dev/null
+++ b/core/embed/projects/bootloader/.changelog.d/5952.fixed
@@ -0,0 +1 @@
+[T3W1] Respect BLE on/off settings in bootloader.
diff --git a/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c b/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
index e1dec1f6..7c44663e 100644
--- a/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
+++ b/core/embed/projects/bootloader/workflow/wf_ble_pairing_request.c
@@ -45,6 +45,8 @@ static bool encode_pairing_code(uint32_t code, uint8_t *outbuf) {
}
workflow_result_t workflow_ble_pairing_request(const fw_info_t *fw) {
+ ble_set_enabled(true);
+
if (!ble_iface_start_pairing()) {
return WF_OK_PAIRING_FAILED;
}
@@ -125,6 +127,8 @@ workflow_result_t workflow_ble_pairing_request(const fw_info_t *fw) {
workflow_result_t workflow_wireless_setup(const fw_info_t *fw,
protob_ios_t *ios) {
+ ble_set_enabled(true);
+
if (!ble_iface_start_pairing()) {
return WF_OK_PAIRING_FAILED;
}
diff --git a/core/embed/sys/backup_ram/inc/sys/backup_ram.h b/core/embed/sys/backup_ram/inc/sys/backup_ram.h
index 4e31d302..b56cb756 100644
--- a/core/embed/sys/backup_ram/inc/sys/backup_ram.h
+++ b/core/embed/sys/backup_ram/inc/sys/backup_ram.h
@@ -22,14 +22,17 @@
#include <trezor_types.h>
/** Global keys for items stored in the backup RAM */
-#define BACKUP_RAM_KEY_PM_RECOVERY 0x0001 // Power management recovery data
+#define BACKUP_RAM_KEY_PM_RECOVERY 0x0001 // Power management recovery data
+#define BACKUP_RAM_KEY_BLE_SETTINGS 0x0002 // BLE settings
/** Maximum size of data stored under a single key in backup RAM */
#define BACKUP_RAM_MAX_KEY_DATA_SIZE 512
typedef enum {
- BACKUP_RAM_ITEM_PUBLIC = 0,
- BACKUP_RAM_ITEM_PROTECTED = 1,
+ BACKUP_RAM_ITEM_PUBLIC =
+ 0, /**< Public data - will be preserved on device wipe */
+ BACKUP_RAM_ITEM_PROTECTED =
+ 1, /**< Protected data - will be erased on device wipe */
} backup_ram_item_type_t;
/**
Why this scored 35/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.