What changed, and why it matters
This commit is a cosmetic/user-interface change. It updates the text and styling shown on the hardware wallet's red error screens (RSOD), such as when a wipe code is entered or too many PIN attempts occur. The messages are rewritten in sentence case instead of all capitals, and some fonts/layouts are adjusted. There is no indication this fixes or introduces a security vulnerability.
No security action required; treat as a normal UI/UX polish commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies error screen strings and rendering styles across C and Rust UI code. It replaces all-caps strings with sentence-case equivalents, introduces new uppercase font styles for title/footer labels in the Caesar layout, removes an unused RSOD header helper in the Eckhart bootloader layout, and updates footer layout calculation. UI test fixture hashes are refreshed to match the new rendered output. No functional security behavior is changed.
Changed components
core/embed/rtl/error_handling.ccore/embed/rust/src/ui/layout_caesar/component/error.rscore/embed/rust/src/ui/layout_caesar/theme/mod.rscore/embed/rust/src/ui/layout_eckhart/bootloader/bld_header.rscore/embed/rust/src/ui/layout_eckhart/component/error.rscore/embed/util/rsod/rsod.ctests/ui_tests/fixtures.jsonInspect captured patch +30 / −25
diff --git a/core/embed/rtl/error_handling.c b/core/embed/rtl/error_handling.c
index 1c91097c..d8a04f2d 100644
--- a/core/embed/rtl/error_handling.c
+++ b/core/embed/rtl/error_handling.c
@@ -27,6 +27,15 @@
uint32_t __stack_chk_guard = 0;
#endif
+#define ALL_DATA_ERASED_MESSAGE "All data has been erased from the device"
+
+#ifdef TREZOR_MODEL_T3W1
+// empty message for T3W1 so that it falls to the more appropriate default
+#define RECONNECT_DEVICE_MESSAGE ""
+#else
+#define RECONNECT_DEVICE_MESSAGE "Please reconnect\nthe device"
+#endif
+
// Calls to this function are inserted by the compiler
// when stack protection is enabled.
void __attribute__((noreturn, used)) __stack_chk_fail(void) {
@@ -52,19 +61,17 @@ __fatal_error(const char *msg, const char *file, int line) {
}
void __attribute__((noreturn)) show_wipe_code_screen(void) {
- error_shutdown_ex("WIPE CODE ENTERED",
- "All data has been erased from the device",
- "PLEASE RECONNECT\nTHE DEVICE");
+ error_shutdown_ex("Wipe code entered", ALL_DATA_ERASED_MESSAGE,
+ RECONNECT_DEVICE_MESSAGE);
}
void __attribute__((noreturn)) show_pin_too_many_screen(void) {
- error_shutdown_ex("PIN ATTEMPTS\nEXCEEDED",
- "All data has been\nerased from the device",
- "Please reconnect the\ndevice");
+ error_shutdown_ex("Pin attempts exceeded", ALL_DATA_ERASED_MESSAGE,
+ RECONNECT_DEVICE_MESSAGE);
}
void __attribute__((noreturn)) show_install_restricted_screen(void) {
- error_shutdown_ex("INSTALL RESTRICTED",
+ error_shutdown_ex("Install restricted",
"Installation of custom firmware is currently restricted.",
- "Please visit\ntrezor.io/bootloader");
+ "Please visit trezor.io/bootloader");
}
diff --git a/core/embed/rust/src/ui/layout_caesar/component/error.rs b/core/embed/rust/src/ui/layout_caesar/component/error.rs
index dd250eb2..647f62ee 100644
--- a/core/embed/rust/src/ui/layout_caesar/component/error.rs
+++ b/core/embed/rust/src/ui/layout_caesar/component/error.rs
@@ -27,9 +27,9 @@ pub struct ErrorScreen<'a> {
impl<'a> ErrorScreen<'a> {
pub fn new(title: TString<'a>, message: TString<'a>, footer: TString<'a>) -> Self {
- let title = Label::centered(title, theme::TEXT_BOLD);
+ let title = Label::centered(title, theme::TEXT_BOLD_UPPER);
let message = Label::centered(message, theme::TEXT_NORMAL).vertically_centered();
- let footer = Label::centered(footer, theme::TEXT_NORMAL).vertically_centered();
+ let footer = Label::centered(footer, theme::TEXT_NORMAL_UPPER).vertically_centered();
Self {
bg: Pad::with_background(BG).with_clear(),
diff --git a/core/embed/rust/src/ui/layout_caesar/theme/mod.rs b/core/embed/rust/src/ui/layout_caesar/theme/mod.rs
index 8db12262..1b1220bd 100644
--- a/core/embed/rust/src/ui/layout_caesar/theme/mod.rs
+++ b/core/embed/rust/src/ui/layout_caesar/theme/mod.rs
@@ -27,6 +27,10 @@ pub const TEXT_NORMAL: TextStyle = TextStyle::new(fonts::FONT_NORMAL, FG, BG, FG
.with_page_breaking(PageBreaking::CutAndInsertEllipsisBoth)
.with_ellipsis_icon(ICON_NEXT_PAGE, ELLIPSIS_ICON_MARGIN)
.with_prev_page_icon(ICON_PREV_PAGE, PREV_PAGE_ICON_MARGIN);
+pub const TEXT_NORMAL_UPPER: TextStyle = TextStyle::new(fonts::FONT_NORMAL_UPPER, FG, BG, FG, FG)
+ .with_page_breaking(PageBreaking::CutAndInsertEllipsisBoth)
+ .with_ellipsis_icon(ICON_NEXT_PAGE, ELLIPSIS_ICON_MARGIN)
+ .with_prev_page_icon(ICON_PREV_PAGE, PREV_PAGE_ICON_MARGIN);
pub const TEXT_BIG: TextStyle = TextStyle::new(fonts::FONT_BIG, FG, BG, FG, FG);
pub const TEXT_CHOICE_ITEMS: TextStyle = TEXT_BIG
.with_line_spacing(2)
diff --git a/core/embed/rust/src/ui/layout_eckhart/bootloader/bld_header.rs b/core/embed/rust/src/ui/layout_eckhart/bootloader/bld_header.rs
index 0d8eb5b4..2e8d6b8a 100644
--- a/core/embed/rust/src/ui/layout_eckhart/bootloader/bld_header.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/bootloader/bld_header.rs
@@ -55,12 +55,6 @@ impl<'a> BldHeader<'a> {
}
}
- pub fn new_rsod_header() -> Self {
- Self::new("Failure".into())
- .with_icon(theme::ICON_INFO, theme::RED)
- .with_text_style(text_title(theme::RED))
- }
-
pub fn new_done(color: Color) -> Self {
Self::new("Done".into())
.with_icon(theme::ICON_DONE, color)
diff --git a/core/embed/rust/src/ui/layout_eckhart/component/error.rs b/core/embed/rust/src/ui/layout_eckhart/component/error.rs
index a7bd6df1..660e0c26 100644
--- a/core/embed/rust/src/ui/layout_eckhart/component/error.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/component/error.rs
@@ -53,20 +53,20 @@ impl<'a> Component for ErrorScreen<'a> {
type Msg = Never;
fn place(&mut self, _bounds: Rect) -> Rect {
- const FOOTER_AREA_HEIGHT: i16 = 52;
const AREA: Rect = SCREEN.inset(SIDE_INSETS);
let (header_area, area) = AREA.split_top(HEADER_HEIGHT);
let (area, actionbar_area) = area.split_bottom(ACTION_BAR_HEIGHT);
let area = area.inset(Insets::bottom(PADDING));
- let (area, footer_area) = area.split_bottom(FOOTER_AREA_HEIGHT);
let title_height = self.title.text_height(area.width());
let message_height = self.message.text_height(area.width());
+ let footer_height = self.footer.text_height(area.width());
let (title_area, area) = area.split_top(title_height);
- let (message_area, _) = area
+ let (message_area, area) = area
.inset(Insets::top(TEXT_VERTICAL_SPACING))
.split_top(message_height);
+ let (_, footer_area) = area.split_bottom(footer_height);
self.header.place(header_area);
self.title.place(title_area);
diff --git a/core/embed/util/rsod/rsod.c b/core/embed/util/rsod/rsod.c
index 3836ac3f..8fdfde28 100644
--- a/core/embed/util/rsod/rsod.c
+++ b/core/embed/util/rsod/rsod.c
@@ -28,10 +28,10 @@
#include <util/scm_revision.h>
#endif
-#define RSOD_DEFAULT_TITLE "INTERNAL ERROR";
-#define RSOD_DEFAULT_MESSAGE "UNSPECIFIED";
-#define RSOD_DEFAULT_FOOTER "PLEASE VISIT TREZOR.IO/RSOD";
-#define RSOD_EXIT_MESSAGE "EXIT %d"
+#define RSOD_DEFAULT_TITLE "Internal error";
+#define RSOD_DEFAULT_MESSAGE "Unspecified";
+#define RSOD_DEFAULT_FOOTER "Please visit trezor.io/rsod";
+#define RSOD_EXIT_MESSAGE "Exit %d"
#ifdef KERNEL_MODE
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 94a1c762..447105e1 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -28206,7 +28206,7 @@
"T3T1_en_test_shamir_persistence.py::test_recovery_multiple_resets": "83ec37ee3f6f09a73a1b4364e71dfec465f29b9c586af127c67bd1575465a1d2",
"T3T1_en_test_shamir_persistence.py::test_recovery_on_old_wallet": "5e10c2031a47ebce57c927754821b7551edf7a1712186c4205b806ae1926598b",
"T3T1_en_test_shamir_persistence.py::test_recovery_single_reset": "7c4a57a42733c5da4e0ee5272345f9a6ef4586522e2c2a5961608f3779a11301",
-"T3T1_en_test_wipe_code.py::test_wipe_code_activate_core": "4c5c188aa81077d4aa77418e379212cb39e6b9b3944d73fdea43d6a2368da701"
+"T3T1_en_test_wipe_code.py::test_wipe_code_activate_core": "d43766115a2b5371ff10bc2821b235397727c3b394a17e6f1718980aca447330"
}
},
"T3W1": {
@@ -37323,7 +37323,7 @@
"T3W1_en_test_shamir_persistence.py::test_abort": "629007f292a56f812d237f3f85bb84c036ceea469625147fa05cdf803610be5a",
"T3W1_en_test_shamir_persistence.py::test_recovery_multiple_resets": "6c577811b4771d419fd4d1ab98597c55d25a19284e2a9f53318a951b96d03a8d",
"T3W1_en_test_shamir_persistence.py::test_recovery_single_reset": "b8f6145edc199971e9a0342128807963240322464622595a3d1471df00e8e325",
-"T3W1_en_test_wipe_code.py::test_wipe_code_activate_core": "a19ee289946bbe6f8dbd96270d3a96e47b8d3853ad26aa54e490005d2d471548"
+"T3W1_en_test_wipe_code.py::test_wipe_code_activate_core": "ea6d6afee2afee99a2d83459038e2755f5cd26c71247aec942ef1e5c061e0ce6"
}
}
}
Why this scored 14/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.