diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 6da1c2d8e..4f7fa1c50 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -340,7 +340,7 @@ int main(void) { mpu_config_off(); // g_boot_command is preserved on STM32U5 - jump_to(BOOTLOADER_START + IMAGE_HEADER_SIZE); + jump_to(IMAGE_CODE_ALIGN(BOOTLOADER_START + IMAGE_HEADER_SIZE)); return 0; } diff --git a/core/embed/boardloader/memory_stm32u5a.ld b/core/embed/boardloader/memory_stm32u5a.ld index 756b43b14..f91099d00 100644 --- a/core/embed/boardloader/memory_stm32u5a.ld +++ b/core/embed/boardloader/memory_stm32u5a.ld @@ -46,7 +46,7 @@ boot_args_start = ORIGIN(BOOT_ARGS); boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); SECTIONS { - .vector_table : ALIGN(512) { + .vector_table : ALIGN(1024) { KEEP(*(.vector_table)); } >FLASH AT>FLASH diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c index c26ecec66..fb570b0c9 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -167,14 +167,14 @@ __attribute__((noreturn)) int main(int argc, char **argv) { bootloader_main(); hal_delay(3000); - jump_to(NULL); + jump_to(0); } void mpu_config_bootloader(void) {} void mpu_config_off(void) {} -__attribute__((noreturn)) void jump_to(void *addr) { +__attribute__((noreturn)) void jump_to(uint32_t address) { bool storage_is_erased = storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]); diff --git a/core/embed/bootloader/emulator.h b/core/embed/bootloader/emulator.h index d73b8bed4..9facab471 100644 --- a/core/embed/bootloader/emulator.h +++ b/core/embed/bootloader/emulator.h @@ -16,7 +16,7 @@ void set_core_clock(int); void mpu_config_bootloader(void); void mpu_config_off(void); void display_set_little_endian(void); -void jump_to(void *addr); +void jump_to(uint32_t address); void ensure_compatible_settings(void); #endif diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 3f8137910..cec5b58b7 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -349,7 +349,7 @@ void real_jump_to_firmware(void) { ensure_compatible_settings(); mpu_config_off(); - jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); } #ifdef STM32U5 diff --git a/core/embed/bootloader/memory_stm32u5a.ld b/core/embed/bootloader/memory_stm32u5a.ld index c45ed1273..e34a7d53e 100644 --- a/core/embed/bootloader/memory_stm32u5a.ld +++ b/core/embed/bootloader/memory_stm32u5a.ld @@ -52,7 +52,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index f59cc4678..e58a1a95b 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -294,7 +294,7 @@ int main(void) { // do not check any trust flags on header, proceed mpu_config_off(); - jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); return 0; } diff --git a/core/embed/bootloader_ci/memory_stm32u5a.ld b/core/embed/bootloader_ci/memory_stm32u5a.ld index 9803e696d..accf76586 100644 --- a/core/embed/bootloader_ci/memory_stm32u5a.ld +++ b/core/embed/bootloader_ci/memory_stm32u5a.ld @@ -52,7 +52,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/firmware/memory_DISC2.ld b/core/embed/firmware/memory_DISC2.ld index a79d3e078..ae6d12729 100644 --- a/core/embed/firmware/memory_DISC2.ld +++ b/core/embed/firmware/memory_DISC2.ld @@ -60,7 +60,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/lib/image.c b/core/embed/lib/image.c index c2eaad3ab..9e0dd20f1 100644 --- a/core/embed/lib/image.c +++ b/core/embed/lib/image.c @@ -245,9 +245,19 @@ secbool check_image_contents(const image_header *const hdr, uint32_t firstskip, } // Check the firmware integrity, calculate and compare hashes - size_t offset = firstskip; + size_t offset = IMAGE_CODE_ALIGN(firstskip); size_t end_offset = offset + hdr->codelen; + // Check area between headers and code + uint32_t padding_size = offset - firstskip; + const uint8_t *addr = + (uint8_t *)flash_area_get_address(area, firstskip, padding_size); + for (size_t i = 0; i < padding_size; i++) { + if (*addr != 0) { + return secfalse; + } + } + while (offset < end_offset) { size_t bytes_to_check = MIN(IMAGE_CHUNK_SIZE - (offset % IMAGE_CHUNK_SIZE), end_offset - offset); diff --git a/core/embed/lib/image.h b/core/embed/lib/image.h index a385b54ee..38869559f 100644 --- a/core/embed/lib/image.h +++ b/core/embed/lib/image.h @@ -35,6 +35,9 @@ #define FIRMWARE_IMAGE_MAGIC 0x465A5254 // TRZF +#define IMAGE_CODE_ALIGN(addr) \ + ((((uint32_t)(uintptr_t)addr) + (CODE_ALIGNMENT - 1)) & ~(CODE_ALIGNMENT - 1)) + typedef struct { uint32_t magic; uint32_t hdrlen; diff --git a/core/embed/models/D001/model_D001.h b/core/embed/models/D001/model_D001.h index 587117342..c0ed20768 100644 --- a/core/embed/models/D001/model_D001.h +++ b/core/embed/models/D001/model_D001.h @@ -23,6 +23,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S #define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/D002/model_D002.h b/core/embed/models/D002/model_D002.h index fbbde2c9a..217974ca6 100644 --- a/core/embed/models/D002/model_D002.h +++ b/core/embed/models/D002/model_D002.h @@ -26,6 +26,7 @@ #define IMAGE_CHUNK_SIZE SIZE_256K #define IMAGE_HASH_SHA256 #define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x400 // SHARED WITH MAKEFILE #define FLASH_START 0x0C000000 diff --git a/core/embed/models/T1B1/model_T1B1.h b/core/embed/models/T1B1/model_T1B1.h index e54613a03..e5006b01e 100644 --- a/core/embed/models/T1B1/model_T1B1.h +++ b/core/embed/models/T1B1/model_T1B1.h @@ -11,6 +11,7 @@ #define IMAGE_CHUNK_SIZE (64 * 1024) #define IMAGE_HASH_SHA256 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/T2B1/model_T2B1.h b/core/embed/models/T2B1/model_T2B1.h index a0bd57dc9..9b384605d 100644 --- a/core/embed/models/T2B1/model_T2B1.h +++ b/core/embed/models/T2B1/model_T2B1.h @@ -23,6 +23,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S #define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/T2T1/model_T2T1.h b/core/embed/models/T2T1/model_T2T1.h index f81464465..47c75409c 100644 --- a/core/embed/models/T2T1/model_T2T1.h +++ b/core/embed/models/T2T1/model_T2T1.h @@ -23,6 +23,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S #define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/T3B1/model_T3B1.h b/core/embed/models/T3B1/model_T3B1.h index 007d2be77..3ed768353 100644 --- a/core/embed/models/T3B1/model_T3B1.h +++ b/core/embed/models/T3B1/model_T3B1.h @@ -24,6 +24,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_SHA256 #define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x0C000000 diff --git a/core/embed/models/T3T1/model_T3T1.h b/core/embed/models/T3T1/model_T3T1.h index e876159dc..28cf69b54 100644 --- a/core/embed/models/T3T1/model_T3T1.h +++ b/core/embed/models/T3T1/model_T3T1.h @@ -24,6 +24,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_SHA256 #define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x0C000000 diff --git a/core/embed/prodtest/memory_stm32u5a.ld b/core/embed/prodtest/memory_stm32u5a.ld index 1cdefad79..fa303b5d4 100644 --- a/core/embed/prodtest/memory_stm32u5a.ld +++ b/core/embed/prodtest/memory_stm32u5a.ld @@ -59,7 +59,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/reflash/memory_stm32u5a.ld b/core/embed/reflash/memory_stm32u5a.ld index be0db29b4..e03a32184 100644 --- a/core/embed/reflash/memory_stm32u5a.ld +++ b/core/embed/reflash/memory_stm32u5a.ld @@ -60,7 +60,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/trezorhal/stm32f4/supervise.c b/core/embed/trezorhal/stm32f4/supervise.c index e3190a391..0ca448306 100644 --- a/core/embed/trezorhal/stm32f4/supervise.c +++ b/core/embed/trezorhal/stm32f4/supervise.c @@ -22,7 +22,8 @@ __attribute__((noreturn)) static void _reboot_to_bootloader( __attribute__((noreturn)) static void _reboot_to_bootloader( boot_command_t boot_command) { mpu_config_bootloader(); - jump_to_with_flag(BOOTLOADER_START + IMAGE_HEADER_SIZE, boot_command); + jump_to_with_flag(IMAGE_CODE_ALIGN(BOOTLOADER_START + IMAGE_HEADER_SIZE), + boot_command); for (;;) ; } diff --git a/python/src/trezorlib/firmware/core.py b/python/src/trezorlib/firmware/core.py index 872787bb7..eda8d0f7f 100644 --- a/python/src/trezorlib/firmware/core.py +++ b/python/src/trezorlib/firmware/core.py @@ -103,19 +103,32 @@ class FirmwareImage(Struct): Consists of firmware header and code block. This is the expected format of firmware binaries for Trezor One, or bootloader images - for Trezor T.""" + for Trezor core models.""" header: FirmwareHeader = subcon(FirmwareHeader) + _header_end: int _code_offset: int code: bytes SUBCON = c.Struct( "header" / FirmwareHeader.SUBCON, + "_header_end" / c.Tell, + "padding" + / c.Padding( + lambda this: FirmwareImage.calc_padding( + this.header.hw_model, this._header_end + ) + ), "_code_offset" / c.Tell, "code" / c.Bytes(c.this.header.code_length), c.Terminated, ) + @staticmethod + def calc_padding(hw_model: bytes, len: int) -> int: + alignment = Model.from_hw_model(hw_model).code_alignment() + return ((len + alignment - 1) & ~(alignment - 1)) - len + def get_hash_params(self) -> "util.FirmwareHashParameters": return Model.from_hw_model(self.header.hw_model).hash_params() @@ -167,7 +180,7 @@ class FirmwareImage(Struct): class VendorFirmware(Struct): """Firmware image prefixed by a vendor header. - This is the expected format of firmware binaries for Trezor T.""" + This is the expected format of firmware binaries for Trezor core models.""" vendor_header: VendorHeader = subcon(VendorHeader) firmware: FirmwareImage = subcon(FirmwareImage) diff --git a/python/src/trezorlib/firmware/models.py b/python/src/trezorlib/firmware/models.py index 46d88cdb7..3d859328b 100644 --- a/python/src/trezorlib/firmware/models.py +++ b/python/src/trezorlib/firmware/models.py @@ -65,6 +65,9 @@ class Model(Enum): def hash_params(self) -> "FirmwareHashParameters": return MODEL_HASH_PARAMS_MAP[self] + def code_alignment(self) -> int: + return MODEL_CODE_ALIGNMENT_MAP[self] + @dataclass class ModelKeys: @@ -331,6 +334,17 @@ MODEL_HASH_PARAMS_MAP = { Model.D002: D002_HASH_PARAMS, } + +MODEL_CODE_ALIGNMENT_MAP = { + Model.T1B1: 0x200, + Model.T2T1: 0x200, + Model.T2B1: 0x200, + Model.T3T1: 0x200, + Model.T3B1: 0x200, + Model.D001: 0x200, + Model.D002: 0x400, +} + # aliases TREZOR_ONE_V1V2 = LEGACY_V1V2