fix(core): don't reuse `Shutdown` exception object
What changed, and why it matters
This commit fixes a minor memory-management issue in the Trezor hardware wallet's user-interface code. Previously, the same `Shutdown` exception object was reused every time a screen layout shut down. Each reuse attached a new traceback to that same object, causing the stored traceback chain to grow indefinitely. The fix creates a fresh exception object each time, so old tracebacks can be garbage-collected. This is a cleanup/robustness fix rather than a clear, exploitable security vulnerability.
Treat as a low-priority hardening fix. Apply the patch in normal release cadence. No urgent security response is warranted unless further evidence shows the growing traceback can be triggered rapidly enough to exhaust device memory and deny service.
Security signals we found
Memory growth / resource exhaustion pattern
Exception object reuse with accumulating traceback
No input validation or trust boundary crossing evident
No changelog entry (routine cleanup marker)
Evidence from the diff
In core/src/trezor/ui/__init__.py the global singleton SHUTDOWN = Shutdown() was removed. The Layout.close() method now raises Shutdown() instead of the shared SHUTDOWN instance. In MicroPython/CPython, re-raising the same exception object accumulates traceback frames on its __traceback__ attribute because the runtime links the current traceback to the existing one. Over many layout shutdown cycles this could cause unbounded memory growth. The patch prevents that by ensuring each shutdown gets a new exception object.
Changed components
core/src/trezor/ui/__init__.pyLayout.close() methodTrezor Core UI shutdown flowInspect captured patch +1 / −3
diff --git a/core/src/trezor/ui/__init__.py b/core/src/trezor/ui/__init__.py
index 55129fc8b..31f63feec 100644
--- a/core/src/trezor/ui/__init__.py
+++ b/core/src/trezor/ui/__init__.py
@@ -82,8 +82,6 @@ class Shutdown(Exception):
pass
-SHUTDOWN = Shutdown()
-
CURRENT_LAYOUT: "Layout | ProgressLayout | None" = None
@@ -355,7 +353,7 @@ class Layout(Generic[T]):
assert self.result_box.is_empty()
self.stop(_kill_taker=False)
self.result_box.put(msg)
- raise SHUTDOWN
+ raise Shutdown()
def create_tasks(self) -> Iterator[loop.Task]:
"""Set up background tasks for a layout.
Why this scored 19/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.