fix(core): improve prodtest linker scripts
What changed, and why it matters
This commit adjusts how the production-test firmware for three Trezor hardware models calculates the length of the code image stored in flash memory. The old calculation added up the sizes of individual sections, which could become inaccurate if the linker layout changed. The new calculation uses a single marker placed at the actual end of the code/data in flash. This is a hardening improvement rather than a fix for an active attack, but an incorrect code-length value could theoretically cause a mis-sized firmware image to be written or verified during manufacturing tests.
Treat as a low-risk hardening commit. Review whether the old `_codelen` formula could have produced an incorrect value in current builds and whether any manufacturing tooling relies on exact `_codelen` values. No urgent action is indicated.
Security signals we found
Linker script change affecting firmware image length calculation
Prodtest (manufacturing test) firmware scope, not end-user firmware
Potential for mis-sized firmware write/verify if length calculation is wrong
No explicit security claim or CVE in commit message
Evidence from the diff
The patch modifies prodtest linker scripts for STM32F4, STM32U58 and STM32U5G. It replaces section-by-section sums used to define _codelen (and _secmon_codelen on U5G) with a unified _image_flash_end symbol computed as LOADADDR(.data) + SIZEOF(.data). This symbol is placed after the .data section’s FLASH load region, which follows .flash (and, on U5G, .secmon_header and .padding). The change makes the code-length measurement robust to future layout changes and avoids double-counting or missing gaps/alignments between sections.
Changed components
core/embed/sys/linker/stm32f4/prodtest.ldcore/embed/sys/linker/stm32u58/prodtest.ldcore/embed/sys/linker/stm32u5g/prodtest.ldInspect captured patch +13 / −4
diff --git a/core/embed/sys/linker/stm32f4/prodtest.ld b/core/embed/sys/linker/stm32f4/prodtest.ld
index f9ba5a7d..7a8efa77 100644
--- a/core/embed/sys/linker/stm32f4/prodtest.ld
+++ b/core/embed/sys/linker/stm32f4/prodtest.ld
@@ -22,7 +22,7 @@ _bss_section_end = ADDR(.bss) + SIZEOF(.bss);
_bootargs_ram_start = BOOTARGS_START;
_bootargs_ram_end = BOOTARGS_START + BOOTARGS_SIZE;
-_codelen = SIZEOF(.flash) + SIZEOF(.data);
+_codelen = _image_flash_end - ADDR(.flash);
SECTIONS {
.vendorheader : ALIGN(4) {
@@ -66,6 +66,9 @@ SECTIONS {
. = ALIGN(512);
} >AUX1_RAM AT>FLASH
+ /* End of code/data in FLASH */
+ _image_flash_end = LOADADDR(.data) + SIZEOF(.data);
+
.bss : ALIGN(4) {
*(.bss*);
. = ALIGN(4);
diff --git a/core/embed/sys/linker/stm32u58/prodtest.ld b/core/embed/sys/linker/stm32u58/prodtest.ld
index 5632a075..ca6c2beb 100644
--- a/core/embed/sys/linker/stm32u58/prodtest.ld
+++ b/core/embed/sys/linker/stm32u58/prodtest.ld
@@ -23,7 +23,7 @@ _bss_section_end = ADDR(.bss) + SIZEOF(.bss);
_bootargs_ram_start = BOOTARGS_START;
_bootargs_ram_end = BOOTARGS_START + BOOTARGS_SIZE;
-_codelen = SIZEOF(.flash) + SIZEOF(.data);
+_codelen = _image_flash_end - ADDR(.flash);
SECTIONS {
.vendorheader : ALIGN(4) {
@@ -63,6 +63,9 @@ SECTIONS {
*(.ARM.exidx*);
}
+ /* End of code/data in FLASH */
+ _image_flash_end = LOADADDR(.data) + SIZEOF(.data);
+
.bss : ALIGN(4) {
*(.bss*);
. = ALIGN(4);
diff --git a/core/embed/sys/linker/stm32u5g/prodtest.ld b/core/embed/sys/linker/stm32u5g/prodtest.ld
index 17ff1a55..7ccd8863 100644
--- a/core/embed/sys/linker/stm32u5g/prodtest.ld
+++ b/core/embed/sys/linker/stm32u5g/prodtest.ld
@@ -22,8 +22,8 @@ _bss_section_end = ADDR(.bss) + SIZEOF(.bss);
_bootargs_ram_start = BOOTARGS_START;
_bootargs_ram_end = BOOTARGS_START + BOOTARGS_SIZE;
-_codelen = SIZEOF(.secmon_header) + SIZEOF(.padding) + SIZEOF(.flash) + SIZEOF(.data);
-_secmon_codelen = SIZEOF(.padding) + SIZEOF(.flash) + SIZEOF(.data);
+_codelen = _image_flash_end - ADDR(.secmon_header);
+_secmon_codelen = _image_flash_end - ADDR(.padding);
SECTIONS {
.vendorheader : ALIGN(4) {
@@ -76,6 +76,9 @@ SECTIONS {
*(.ARM.exidx*);
}
+ /* End of code/data in FLASH */
+ _image_flash_end = LOADADDR(.data) + SIZEOF(.data);
+
.bss : ALIGN(4) {
*(.no_dma_buffers*);
*(.bss*);
Why this scored 21/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.