What changed, and why it matters
This commit replaces a custom-built notification helper (a 'waker') inside the BitBox02 firmware's Rust code with a built-in, memory-safe no-op version. The old helper used heap memory and reference counting (Arc), which could be freed by interrupt routines while the memory allocator was already busy. The change removes that helper entirely and uses a static no-op waker instead, preventing a potential use-after-free or heap corruption issue during asynchronous task polling.
Treat this as a defensive hardening fix with potential security relevance. Review whether any other code paths still use heap-backed wakers or Arc-backed callbacks in interrupt contexts. No immediate user action is required beyond applying the firmware update.
Security signals we found
Eliminates heap-allocated Arc in waker construction
Removes custom RawWakerVTable with unsafe clone/wake/drop operations
Prevents ISR callbacks from freeing Arc while heap allocator is active
Uses core::task::Waker::noop() static no-op waker
Commit message explicitly describes the safety motivation
Evidence from the diff
The firmware’s polling executor calls spin() on every main-loop iteration and ignores wake notifications. Previously, spin() created a Waker via a heap-backed waker_fn helper that allocated an Arc
Changed components
src/rust/util/src/bb02_async.rssrc/rust/util/src/waker_fn.rssrc/rust/util/src/lib.rsInspect captured patch +2 / −52
diff --git a/src/rust/util/src/bb02_async.rs b/src/rust/util/src/bb02_async.rs
index 66ac720..ba982fa 100644
--- a/src/rust/util/src/bb02_async.rs
+++ b/src/rust/util/src/bb02_async.rs
@@ -13,10 +13,8 @@ pub type Task<'a, O> = Pin<Box<dyn core::future::Future<Output = O> + 'a>>;
/// A primitive poll invocation for a task, with no waking functionality.
pub fn spin<O>(task: &mut Task<O>) -> Poll<O> {
- // TODO: statically allocate the context.
- let waker = crate::waker_fn::waker_fn(|| {});
- let context = &mut Context::from_waker(&waker);
- task.as_mut().poll(context)
+ let mut context = Context::from_waker(core::task::Waker::noop());
+ task.as_mut().poll(&mut context)
}
/// Implements the Option future, see `option()`.
diff --git a/src/rust/util/src/lib.rs b/src/rust/util/src/lib.rs
index 597742f..b343be2 100644
--- a/src/rust/util/src/lib.rs
+++ b/src/rust/util/src/lib.rs
@@ -12,7 +12,6 @@ pub mod futures;
pub mod log;
pub mod name;
pub mod strings;
-mod waker_fn;
#[cfg(feature = "p256")]
mod p256;
diff --git a/src/rust/util/src/waker_fn.rs b/src/rust/util/src/waker_fn.rs
deleted file mode 100644
index 16a94b4..0000000
--- a/src/rust/util/src/waker_fn.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// This file was taken from here:
-// https://github.com/async-rs/async-task/blob/b7a249680490991f92cc2144d4eff65e4effb3b7/src/waker_fn.rs
-// https://github.com/async-rs/async-task/blob/b7a249680490991f92cc2144d4eff65e4effb3b7/LICENSE-APACHE
-
-use alloc::sync::Arc;
-use core::mem::{self, ManuallyDrop};
-use core::task::{RawWaker, RawWakerVTable, Waker};
-
-/// Creates a waker from a wake function.
-///
-/// The function gets called every time the waker is woken.
-pub fn waker_fn<F: Fn() + Send + Sync + 'static>(f: F) -> Waker {
- let raw = Arc::into_raw(Arc::new(f)) as *const ();
- let vtable = &Helper::<F>::VTABLE;
- unsafe { Waker::from_raw(RawWaker::new(raw, vtable)) }
-}
-
-struct Helper<F>(F);
-
-impl<F: Fn() + Send + Sync + 'static> Helper<F> {
- const VTABLE: RawWakerVTable = RawWakerVTable::new(
- Self::clone_waker,
- Self::wake,
- Self::wake_by_ref,
- Self::drop_waker,
- );
-
- unsafe fn clone_waker(ptr: *const ()) -> RawWaker {
- let arc = ManuallyDrop::new(unsafe { Arc::from_raw(ptr as *const F) });
- mem::forget(arc.clone());
- RawWaker::new(ptr, &Self::VTABLE)
- }
-
- unsafe fn wake(ptr: *const ()) {
- let arc = unsafe { Arc::from_raw(ptr as *const F) };
- (arc)();
- }
-
- unsafe fn wake_by_ref(ptr: *const ()) {
- let arc = ManuallyDrop::new(unsafe { Arc::from_raw(ptr as *const F) });
- (arc)();
- }
-
- unsafe fn drop_waker(ptr: *const ()) {
- drop(unsafe { Arc::from_raw(ptr as *const F) });
- }
-}
Why this scored 57/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.