What changed, and why it matters
This commit refactors how the BitBox02 hardware wallet resets its USB communication watchdog during long-running operations. It introduces a new method in the hardware abstraction layer so Rust code can reset the timeout without directly calling a lower-level USB module. The change itself is a structural cleanup; it does not appear to fix or introduce a security vulnerability, but it touches code that prevents tasks from being cancelled while handling sensitive operations like seed encryption and device reset.
No immediate action required. Treat as a normal refactoring commit. If reviewing for security, verify that the abstraction does not allow callers to set unsafe timeout values and that the underlying `usb_processing::timeout_reset` behavior remains unchanged.
Security signals we found
Touches timeout/watchdog logic for long-running cryptographic operations
Refactors sensitive code paths: seed encryption, unlock, and device reset
No change to timeout values or underlying timeout implementation
No input validation changes or boundary checks added
Evidence from the diff
The patch adds communication_timeout_reset(value: i16) to the System trait in bitbox-hal, implements it in the real BitBox02System by delegating to crate::usb_processing::timeout_reset, and provides a no-op stub for the testing HAL. Existing call sites in keystore.rs (seed encryption and unlock) and reset.rs are updated to use the new abstraction instead of calling bitbox02::usb_processing::timeout_reset directly. The behavior is functionally unchanged: the same timeout values (LONG_TIMEOUT) are passed to the same underlying function.
Changed components
src/rust/bitbox-hal/src/system.rssrc/rust/bitbox02-rust/src/hal/testing/system.rssrc/rust/bitbox02-rust/src/keystore.rssrc/rust/bitbox02-rust/src/reset.rssrc/rust/bitbox02/src/hal/system.rsInspect captured patch +19 / −4
diff --git a/src/rust/bitbox-hal/src/system.rs b/src/rust/bitbox-hal/src/system.rs
index ed1983b..330b9a8 100644
--- a/src/rust/bitbox-hal/src/system.rs
+++ b/src/rust/bitbox-hal/src/system.rs
@@ -9,6 +9,15 @@ pub trait System {
/// and the (possibly empty) device name.
async fn startup();
+ /// Reset the communication timeout watchdog for outstanding operations.
+ ///
+ /// This watchdog tracks the amount of time to wait before an outstanding
+ /// operation times out (for example, if the client closes).
+ /// Use this for long running operations that are expected to take longer
+ /// than about 300ms (a bit less than the 500ms timeout before a task is
+ /// cancelled).
+ fn communication_timeout_reset(&mut self, value: i16);
+
fn reboot(&mut self) -> !;
fn reboot_to_bootloader(&mut self) -> !;
fn reset_ble(&mut self);
diff --git a/src/rust/bitbox02-rust/src/hal/testing/system.rs b/src/rust/bitbox02-rust/src/hal/testing/system.rs
index c57f50e..1a4cd8a 100644
--- a/src/rust/bitbox02-rust/src/hal/testing/system.rs
+++ b/src/rust/bitbox02-rust/src/hal/testing/system.rs
@@ -21,6 +21,8 @@ impl TestingSystem {
impl crate::hal::System for TestingSystem {
async fn startup() {}
+ fn communication_timeout_reset(&mut self, _value: i16) {}
+
fn reboot(&mut self) -> ! {
panic!("reboot called")
}
diff --git a/src/rust/bitbox02-rust/src/keystore.rs b/src/rust/bitbox02-rust/src/keystore.rs
index a81b0a3..50f4a1d 100644
--- a/src/rust/bitbox02-rust/src/keystore.rs
+++ b/src/rust/bitbox02-rust/src/keystore.rs
@@ -7,7 +7,7 @@ use alloc::string::String;
use alloc::vec::Vec;
use crate::bip32;
-use crate::hal::{Memory, Random, SecureChip, memory, securechip};
+use crate::hal::{Memory, Random, SecureChip, System, memory, securechip};
use util::bip32::HARDENED;
use util::cell::SyncCell;
@@ -288,7 +288,7 @@ fn encrypt_and_store_seed_internal(
// Lock to ensure clean RAM
lock();
- bitbox02::usb_processing::timeout_reset(LONG_TIMEOUT);
+ hal.system().communication_timeout_reset(LONG_TIMEOUT);
let password_stretch_algo = default_password_stretch_algo(hal)?;
@@ -428,7 +428,7 @@ pub async fn unlock(
crate::reset::reset(hal, false).await;
return Err(Error::MaxAttemptsExceeded);
}
- bitbox02::usb_processing::timeout_reset(LONG_TIMEOUT);
+ hal.system().communication_timeout_reset(LONG_TIMEOUT);
hal.memory().increment_unlock_attempts();
let seed = match get_and_decrypt_seed(hal, password) {
Ok(seed) => seed,
diff --git a/src/rust/bitbox02-rust/src/reset.rs b/src/rust/bitbox02-rust/src/reset.rs
index e63b866..a908ff3 100644
--- a/src/rust/bitbox02-rust/src/reset.rs
+++ b/src/rust/bitbox02-rust/src/reset.rs
@@ -17,7 +17,7 @@ pub(crate) async fn reset(hal: &mut impl crate::hal::Hal, status: bool) {
// 7 seconds (longer than needed) so we don't assume communication was lost and this task gets
// dropped at an await point.
const LONG_TIMEOUT: i16 = -70;
- bitbox02::usb_processing::timeout_reset(LONG_TIMEOUT);
+ hal.system().communication_timeout_reset(LONG_TIMEOUT);
// Reset secure chip keys and U2F counter with retries. We retry in case there are transient
// errors.
diff --git a/src/rust/bitbox02/src/hal/system.rs b/src/rust/bitbox02/src/hal/system.rs
index 83ae393..7332dc1 100644
--- a/src/rust/bitbox02/src/hal/system.rs
+++ b/src/rust/bitbox02/src/hal/system.rs
@@ -19,6 +19,10 @@ impl System for BitBox02System {
crate::ui::screen_process_waiting_switch_to_lockscreen();
}
+ fn communication_timeout_reset(&mut self, value: i16) {
+ crate::usb_processing::timeout_reset(value);
+ }
+
#[allow(clippy::empty_loop)]
fn reboot(&mut self) -> ! {
unsafe { bitbox02_sys::reboot() }
Why this scored 17/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.