diff --git a/core/SConscript.firmware b/core/SConscript.firmware index d5b968405e..1f737b044f 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -468,6 +468,7 @@ ALLPATHS = [ 'embed/models', 'embed/gfx/inc', 'embed/sys/bsp/inc', + 'embed/util/bl_check/inc', 'embed/util/image/inc', 'embed/util/rsod/inc', 'embed/util/scm_revision/inc', @@ -907,6 +908,16 @@ if 'nrf' in FEATURES_AVAILABLE: f'embed/models/{TREZOR_MODEL}/trezor-ble.bin', ) +tools.embed_compressed_binary( + obj_program, + env, + 'bootloader', + 'embed/projects/bootloaders/bootloader.o', + f'embed/models/{TREZOR_MODEL}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', + 'firmware', + 'bootloader', + ) + env.Depends(obj_program, qstr_generated) linkerscript_gen = env.Command( diff --git a/core/SConscript.kernel b/core/SConscript.kernel index 1abbf2576b..d981a1df8c 100644 --- a/core/SConscript.kernel +++ b/core/SConscript.kernel @@ -408,16 +408,6 @@ obj_program.extend( ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' ' $SOURCE $TARGET', )) -tools.embed_compressed_binary( - obj_program, - env, - 'bootloader', - 'embed/projects/bootloaders/bootloader.o', - f'embed/models/{TREZOR_MODEL}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', - 'kernel', - 'bootloader', - ) - if "secmon_layout" in FEATURES_AVAILABLE: tools.embed_raw_binary( obj_program, diff --git a/core/SConscript.secmon b/core/SConscript.secmon index a761f5c1c3..f03f144013 100644 --- a/core/SConscript.secmon +++ b/core/SConscript.secmon @@ -361,10 +361,6 @@ cmake_gen = env.Command( action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS', ) -BOOTLOADER_SUFFIX = TREZOR_MODEL -if BOOTLOADER_QA: - BOOTLOADER_SUFFIX += '_qa' - # select vendor header if BOOTLOADER_QA or BOOTLOADER_DEVEL: vendor = "dev_DO_NOT_SIGN_signed_dev" @@ -389,16 +385,6 @@ obj_program.extend( ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' ' $SOURCE $TARGET', )) -tools.embed_compressed_binary( - obj_program, - env, - 'bootloader', - 'embed/projects/bootloaders/bootloader.o', - f'embed/models/{TREZOR_MODEL}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', - 'secmon', - 'bootloader', - ) - linkerscript_gen = env.Command( target='memory.ld', source=[f'embed/models/{TREZOR_MODEL}/memory_secmon.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='secmon')], diff --git a/core/embed/projects/firmware/main.c b/core/embed/projects/firmware/main.c index f6c34b735b..de36b34537 100644 --- a/core/embed/projects/firmware/main.c +++ b/core/embed/projects/firmware/main.c @@ -37,13 +37,33 @@ #include #include #include +#include #include #include "rust_ui_common.h" +#include + #ifdef USE_SECP256K1_ZKP #include "zkp_context.h" #endif +#define CONCAT_NAME_HELPER(prefix, name, suffix) prefix##name##suffix +#define CONCAT_NAME(name, var) CONCAT_NAME_HELPER(BOOTLOADER_, name, var) + +#if BOOTLOADER_QA +// QA bootloaders +#define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_00) +#define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_FF) +#else +// normal bootloaders +#define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _00) +#define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _FF) +#endif + +// symbols from bootloader.bin => bootloader.o +extern const void _deflated_bootloader_start; +extern const void _deflated_bootloader_size; + #ifdef USE_NRF #include @@ -62,14 +82,47 @@ int main_func(uint32_t cmd, void *arg) { bool fading = DISPLAY_JUMP_BEHAVIOR == DISPLAY_RESET_CONTENT; -#ifdef USE_NRF - if (nrf_update_required(&nrf_app_start, (size_t)&nrf_app_size)) { - screen_update(); - nrf_update(&nrf_app_start, (size_t)&nrf_app_size); - fading = true; - } + bool update_required = false; + +#if PRODUCTION || BOOTLOADER_QA + + // replace bootloader with the latest one + const uint8_t *data = (const uint8_t *)&_deflated_bootloader_start; + const size_t len = (size_t)&_deflated_bootloader_size; + + uint8_t hash_00[] = BOOTLOADER_00; + uint8_t hash_FF[] = BOOTLOADER_FF; + + // Check if the boardloader is valid and replace it if not + bool bl_update_required = + bl_check_check(hash_00, hash_FF, BLAKE2S_DIGEST_LENGTH); + update_required = update_required || bl_update_required; + #endif +#ifdef USE_NRF + bool nrf_update_required_ = + nrf_update_required(&nrf_app_start, (size_t)&nrf_app_size); + update_required = update_required || nrf_update_required_; +#endif + + if (update_required) { + screen_update(); + fading = true; + +#if PRODUCTION || BOOTLOADER_QA + if (bl_update_required) { + bl_check_replace(data, len); + } +#endif + +#ifdef USE_NRF + if (nrf_update_required_) { + nrf_update(&nrf_app_start, (size_t)&nrf_app_size); + } +#endif + } + screen_boot_stage_2(fading); #ifdef USE_SECP256K1_ZKP diff --git a/core/embed/projects/kernel/main.c b/core/embed/projects/kernel/main.c index fb0dfe728a..0d6d88de55 100644 --- a/core/embed/projects/kernel/main.c +++ b/core/embed/projects/kernel/main.c @@ -157,9 +157,6 @@ void drivers_init() { check_oem_keys(); #endif -#if PRODUCTION || BOOTLOADER_QA - check_and_replace_bootloader(); -#endif #endif #ifdef USE_BUTTON diff --git a/core/embed/projects/secmon/main.c b/core/embed/projects/secmon/main.c index b48a1beb9a..9c591436cd 100644 --- a/core/embed/projects/secmon/main.c +++ b/core/embed/projects/secmon/main.c @@ -77,10 +77,6 @@ static void drivers_init(void) { check_oem_keys(); #endif -#if PRODUCTION || BOOTLOADER_QA - check_and_replace_bootloader(); -#endif - #ifdef USE_OPTIGA optiga_init_and_configure(); #endif diff --git a/core/embed/rust/src/ui/layout_bolt/mod.rs b/core/embed/rust/src/ui/layout_bolt/mod.rs index 5949dc4a23..c4e977a3fb 100644 --- a/core/embed/rust/src/ui/layout_bolt/mod.rs +++ b/core/embed/rust/src/ui/layout_bolt/mod.rs @@ -80,14 +80,7 @@ impl CommonUI for UIBolt { show(&mut frame, fade_in); } - fn screen_update() { - let mut frame = ErrorScreen::new( - "Update".into(), - "Finishing firmware update".into(), - "Do not turn off your Trezor".into(), - ); - show(&mut frame, true); - } + fn screen_update() {} #[cfg(feature = "ui_debug_overlay")] fn render_debug_overlay<'s>(_target: &mut impl shape::Renderer<'s>, _info: DebugOverlay) { diff --git a/core/embed/rust/src/ui/layout_caesar/mod.rs b/core/embed/rust/src/ui/layout_caesar/mod.rs index 0439496559..21e47ae932 100644 --- a/core/embed/rust/src/ui/layout_caesar/mod.rs +++ b/core/embed/rust/src/ui/layout_caesar/mod.rs @@ -38,9 +38,7 @@ impl CommonUI for UICaesar { show(&mut frame, fade_in); } - fn screen_update() { - unimplemented!() - } + fn screen_update() {} #[cfg(feature = "ui_debug_overlay")] fn render_debug_overlay<'s>(_target: &mut impl shape::Renderer<'s>, _info: DebugOverlay) { diff --git a/core/embed/rust/src/ui/layout_delizia/mod.rs b/core/embed/rust/src/ui/layout_delizia/mod.rs index 0afa136cad..25e0946767 100644 --- a/core/embed/rust/src/ui/layout_delizia/mod.rs +++ b/core/embed/rust/src/ui/layout_delizia/mod.rs @@ -86,9 +86,7 @@ impl CommonUI for UIDelizia { show(&mut frame, fade_in); } - fn screen_update() { - unimplemented!() - } + fn screen_update() {} #[cfg(feature = "ui_debug_overlay")] fn render_debug_overlay<'s>(target: &mut impl shape::Renderer<'s>, info: DebugOverlay) { diff --git a/core/embed/sys/linker/stm32f4/firmware.ld b/core/embed/sys/linker/stm32f4/firmware.ld index 0cfa4db9bf..3b5cc393c6 100644 --- a/core/embed/sys/linker/stm32f4/firmware.ld +++ b/core/embed/sys/linker/stm32f4/firmware.ld @@ -53,6 +53,8 @@ SECTIONS { . = ALIGN(4); *(.rodata*); . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH diff --git a/core/embed/sys/linker/stm32f4/kernel.ld b/core/embed/sys/linker/stm32f4/kernel.ld index 13317babc0..5a7bf23f36 100644 --- a/core/embed/sys/linker/stm32f4/kernel.ld +++ b/core/embed/sys/linker/stm32f4/kernel.ld @@ -44,9 +44,6 @@ SECTIONS { *(.text*); . = ALIGN(4); *(.rodata*); - . = ALIGN(4); - KEEP(*(.bootloader)); - *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH diff --git a/core/embed/sys/linker/stm32u58/firmware.ld b/core/embed/sys/linker/stm32u58/firmware.ld index 9e73d648aa..77d5db8b1c 100644 --- a/core/embed/sys/linker/stm32u58/firmware.ld +++ b/core/embed/sys/linker/stm32u58/firmware.ld @@ -44,6 +44,9 @@ SECTIONS { *(.text*); . = ALIGN(4); *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH diff --git a/core/embed/sys/linker/stm32u58/kernel.ld b/core/embed/sys/linker/stm32u58/kernel.ld index a2a5d64d20..89ae952e89 100644 --- a/core/embed/sys/linker/stm32u58/kernel.ld +++ b/core/embed/sys/linker/stm32u58/kernel.ld @@ -45,9 +45,6 @@ SECTIONS { *(.text*); . = ALIGN(4); *(.rodata*); - . = ALIGN(4); - KEEP(*(.bootloader)); - *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH diff --git a/core/embed/sys/linker/stm32u5g/firmware.ld b/core/embed/sys/linker/stm32u5g/firmware.ld index df9fbe8054..c52b0400fc 100644 --- a/core/embed/sys/linker/stm32u5g/firmware.ld +++ b/core/embed/sys/linker/stm32u5g/firmware.ld @@ -49,6 +49,9 @@ SECTIONS { . = ALIGN(4); KEEP(*(.nrf_app)); *(.nrf_app*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH diff --git a/core/embed/sys/linker/stm32u5g/kernel.ld b/core/embed/sys/linker/stm32u5g/kernel.ld index 879e4905e2..dc4ab78ed8 100644 --- a/core/embed/sys/linker/stm32u5g/kernel.ld +++ b/core/embed/sys/linker/stm32u5g/kernel.ld @@ -49,9 +49,6 @@ SECTIONS { *(.text*); . = ALIGN(4); *(.rodata*); - . = ALIGN(4); - KEEP(*(.bootloader)); - *(.bootloader*); . = ALIGN(512); } >FLASH AT>FLASH diff --git a/core/embed/sys/linker/stm32u5g/secmon.ld b/core/embed/sys/linker/stm32u5g/secmon.ld index 5d180ada98..fc2113d191 100644 --- a/core/embed/sys/linker/stm32u5g/secmon.ld +++ b/core/embed/sys/linker/stm32u5g/secmon.ld @@ -55,9 +55,6 @@ SECTIONS { *(.text*); . = ALIGN(4); *(.rodata*); - . = ALIGN(4); - KEEP(*(.bootloader)); - *(.bootloader*); . = ALIGN(512); } >FLASH diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c index f72d7f9eef..990672aac8 100644 --- a/core/embed/sys/smcall/stm32/smcall_dispatch.c +++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c @@ -49,6 +49,8 @@ #include #endif +#include + #include "smcall_numbers.h" #include "smcall_probe.h" #include "smcall_verifiers.h" @@ -68,6 +70,19 @@ __attribute((no_stack_protector)) void smcall_handler(uint32_t *args, bootargs_get_args__verified(boot_args); } break; + case SMCALL_BL_CHECK_CHECK: { + const uint8_t *hash_00 = (const uint8_t *)args[0]; + const uint8_t *hash_FF = (const uint8_t *)args[1]; + size_t hash_len = args[2]; + args[0] = bl_check_check__verified(hash_00, hash_FF, hash_len); + } break; + + case SMCALL_BL_CHECK_REPLACE: { + const uint8_t *data = (const uint8_t *)args[0]; + size_t len = args[1]; + bl_check_replace__verified(data, len); + } break; + case SMCALL_GET_BOARD_NAME: { args[0] = get_board_name(); } break; diff --git a/core/embed/sys/smcall/stm32/smcall_numbers.h b/core/embed/sys/smcall/stm32/smcall_numbers.h index af366f83d1..47f5d785ce 100644 --- a/core/embed/sys/smcall/stm32/smcall_numbers.h +++ b/core/embed/sys/smcall/stm32/smcall_numbers.h @@ -33,6 +33,9 @@ typedef enum { SMCALL_BOOTARGS_SET = 1, SMCALL_BOOTARGS_GET_ARGS, + SMCALL_BL_CHECK_CHECK, + SMCALL_BL_CHECK_REPLACE, + SMCALL_REBOOT_DEVICE, SMCALL_REBOOT_TO_BOOTLOADER, SMCALL_REBOOT_AND_UPGRADE, diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c index 7f13427d4b..d6845d5114 100644 --- a/core/embed/sys/smcall/stm32/smcall_stubs.c +++ b/core/embed/sys/smcall/stm32/smcall_stubs.c @@ -35,6 +35,19 @@ void bootargs_set(boot_command_t command, const void *args, size_t args_size) { void bootargs_get_args(boot_args_t *args) { smcall_invoke1((uint32_t)args, SMCALL_BOOTARGS_GET_ARGS); } +// ============================================================================= +// bl_check.h +// ============================================================================= + +bool bl_check_check(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len) { + return (bool)smcall_invoke3((uint32_t)hash_00, (uint32_t)hash_FF, + (uint32_t)hash_len, SMCALL_BL_CHECK_CHECK); +} + +void bl_check_replace(const uint8_t *data, size_t len) { + smcall_invoke2((uint32_t)data, len, SMCALL_BL_CHECK_REPLACE); +} // ============================================================================= // board_capabilities.h diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.c b/core/embed/sys/smcall/stm32/smcall_verifiers.c index b95028c0ba..2af8aa1666 100644 --- a/core/embed/sys/smcall/stm32/smcall_verifiers.c +++ b/core/embed/sys/smcall/stm32/smcall_verifiers.c @@ -60,6 +60,37 @@ access_violation: // --------------------------------------------------------------------- +bool bl_check_check__verified(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len) { + if (!probe_read_access(hash_00, hash_len)) { + goto access_violation; + } + + if (!probe_read_access(hash_FF, hash_len)) { + goto access_violation; + } + + return bl_check_check(hash_00, hash_FF, hash_len); + +access_violation: + apptask_access_violation(); + return false; +} + +void bl_check_replace__verified(const uint8_t *data, size_t len) { + if (!probe_read_access(data, len)) { + goto access_violation; + } + + bl_check_replace(data, len); + return; + +access_violation: + apptask_access_violation(); +} + +// --------------------------------------------------------------------- + void reboot_and_upgrade__verified(const uint8_t hash[32]) { if (!probe_read_access(hash, 32)) { goto access_violation; diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.h b/core/embed/sys/smcall/stm32/smcall_verifiers.h index 6bf9cf2a3a..89e3fb43f9 100644 --- a/core/embed/sys/smcall/stm32/smcall_verifiers.h +++ b/core/embed/sys/smcall/stm32/smcall_verifiers.h @@ -29,6 +29,15 @@ void bootargs_set__verified(boot_command_t command, const void *args, void bootargs_get_args__verified(boot_args_t *args); +// --------------------------------------------------------------------- + +#include + +bool bl_check_check__verified(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len); + +void bl_check_replace__verified(const uint8_t *data, size_t len); + // --------------------------------------------------------------------- #include diff --git a/core/embed/sys/syscall/inc/sys/syscall_numbers.h b/core/embed/sys/syscall/inc/sys/syscall_numbers.h index 2e90ecefc2..1580c0a667 100644 --- a/core/embed/sys/syscall/inc/sys/syscall_numbers.h +++ b/core/embed/sys/syscall/inc/sys/syscall_numbers.h @@ -42,6 +42,9 @@ typedef enum { SYSCALL_SYSEVENTS_POLL, + SYSCALL_BL_CHECK_CHECK, + SYSCALL_BL_CHECK_REPLACE, + SYSCALL_REBOOT_DEVICE, SYSCALL_REBOOT_TO_BOOTLOADER, SYSCALL_REBOOT_AND_UPGRADE, diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c index 87eeb0688c..3b185a58f8 100644 --- a/core/embed/sys/syscall/stm32/syscall_dispatch.c +++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c @@ -81,6 +81,10 @@ #include #endif +#if PRODUCTION || BOOTLOADER_QA +#include +#endif + #include "syscall_context.h" #include "syscall_internal.h" #include "syscall_verifiers.h" @@ -166,6 +170,19 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args, } } break; + case SYSCALL_BL_CHECK_CHECK: { + const uint8_t *hash_00 = (const uint8_t *)args[0]; + const uint8_t *hash_FF = (const uint8_t *)args[1]; + size_t hash_len = args[2]; + args[0] = bl_check_check__verified(hash_00, hash_FF, hash_len); + } break; + + case SYSCALL_BL_CHECK_REPLACE: { + const uint8_t *data = (const uint8_t *)args[0]; + size_t len = args[1]; + bl_check_replace__verified(data, len); + } break; + case SYSCALL_REBOOT_DEVICE: { reboot_device(); } break; diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c index 59a35eb7d4..19cbdf3ee5 100644 --- a/core/embed/sys/syscall/stm32/syscall_stubs.c +++ b/core/embed/sys/syscall/stm32/syscall_stubs.c @@ -84,6 +84,20 @@ void sysevents_poll(const sysevents_t *awaited, sysevents_t *signalled, SYSCALL_SYSEVENTS_POLL); } +// ============================================================================= +// bl_check.h +// ============================================================================= + +bool bl_check_check(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len) { + return (bool)syscall_invoke3((uint32_t)hash_00, (uint32_t)hash_FF, + (uint32_t)hash_len, SYSCALL_BL_CHECK_CHECK); +} + +void bl_check_replace(const uint8_t *data, size_t len) { + syscall_invoke2((uint32_t)data, len, SYSCALL_BL_CHECK_REPLACE); +} + // ============================================================================= // bootutils.h // ============================================================================= diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.c b/core/embed/sys/syscall/stm32/syscall_verifiers.c index 4fea54a49e..a06218bfc9 100644 --- a/core/embed/sys/syscall/stm32/syscall_verifiers.c +++ b/core/embed/sys/syscall/stm32/syscall_verifiers.c @@ -64,6 +64,37 @@ access_violation: // --------------------------------------------------------------------- +bool bl_check_check__verified(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len) { + if (!probe_read_access(hash_00, hash_len)) { + goto access_violation; + } + + if (!probe_read_access(hash_FF, hash_len)) { + goto access_violation; + } + + return bl_check_check(hash_00, hash_FF, hash_len); + +access_violation: + apptask_access_violation(); + return false; +}; + +void bl_check_replace__verified(const uint8_t *data, size_t len) { + if (!probe_read_access(data, len)) { + goto access_violation; + } + + bl_check_replace(data, len); + return; + +access_violation: + apptask_access_violation(); +} + +// --------------------------------------------------------------------- + void system_exit__verified(int exit_code) { systask_t *task = systask_active(); diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.h b/core/embed/sys/syscall/stm32/syscall_verifiers.h index 7864ef8e93..6c313336e1 100644 --- a/core/embed/sys/syscall/stm32/syscall_verifiers.h +++ b/core/embed/sys/syscall/stm32/syscall_verifiers.h @@ -44,6 +44,14 @@ void system_exit_fatal__verified(const char *message, size_t message_len, void reboot_and_upgrade__verified(const uint8_t hash[32]); +// --------------------------------------------------------------------- + +bool bl_check_check__verified(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len); + +#include +void bl_check_replace__verified(const uint8_t *data, size_t len); + // --------------------------------------------------------------------- #include diff --git a/core/embed/util/bl_check/bl_check.c b/core/embed/util/bl_check/bl_check.c index 0ff1ef3173..19de388b56 100644 --- a/core/embed/util/bl_check/bl_check.c +++ b/core/embed/util/bl_check/bl_check.c @@ -30,40 +30,15 @@ #include "memzero.h" #include "uzlib.h" -// symbols from bootloader.bin => bootloader.o -extern const void _deflated_bootloader_start; -extern const void _deflated_bootloader_size; - -#define CONCAT_NAME_HELPER(prefix, name, suffix) prefix##name##suffix -#define CONCAT_NAME(name, var) CONCAT_NAME_HELPER(BOOTLOADER_, name, var) - -#if BOOTLOADER_QA -// QA bootloaders -#define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_00) -#define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_FF) -#else -// normal bootloaders -#define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _00) -#define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _FF) -#endif -// clang-format on - -#if PRODUCTION || BOOTLOADER_QA -static secbool latest_bootloader(const uint8_t *hash, int len) { - if (len != 32) return secfalse; - - uint8_t hash_00[] = BOOTLOADER_00; - uint8_t hash_FF[] = BOOTLOADER_FF; - - if (0 == memcmp(hash, hash_00, 32)) return sectrue; - if (0 == memcmp(hash, hash_FF, 32)) return sectrue; +static secbool hash_match(const uint8_t *hash, const uint8_t *hash_00, + const uint8_t *hash_FF) { + if (0 == memcmp(hash, hash_00, BLAKE2S_DIGEST_LENGTH)) return sectrue; + if (0 == memcmp(hash, hash_FF, BLAKE2S_DIGEST_LENGTH)) return sectrue; return secfalse; } -#endif #define UZLIB_WINDOW_SIZE (1 << 10) -#if PRODUCTION || BOOTLOADER_QA static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window, const void *src, uint32_t srcsize, void *dest, uint32_t destsize) { @@ -78,12 +53,15 @@ static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window, decomp->dest_limit = decomp->dest + destsize; uzlib_uncompress_init(decomp, window, window ? UZLIB_WINDOW_SIZE : 0); } -#endif -void check_and_replace_bootloader(void) { -#if PRODUCTION || BOOTLOADER_QA +bool bl_check_check(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len) { mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTUPDATE); + if (hash_len != BLAKE2S_DIGEST_LENGTH) { + error_shutdown("Invalid bootloader hash length"); + } + // compute current bootloader hash uint8_t hash[BLAKE2S_DIGEST_LENGTH]; const uint32_t bl_len = flash_area_get_size(&BOOTLOADER_AREA); @@ -94,15 +72,21 @@ void check_and_replace_bootloader(void) { // ensure(known_bootloader(hash, BLAKE2S_DIGEST_LENGTH), "Unknown bootloader // detected"); - // do we have the latest bootloader? - if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) { + // does the bootloader match? + if (sectrue == hash_match(hash, hash_00, hash_FF)) { mpu_reconfig(mode); - return; + return false; } - // replace bootloader with the latest one - const uint32_t *data = (const uint32_t *)&_deflated_bootloader_start; - const uint32_t len = (const uint32_t)&_deflated_bootloader_size; + mpu_reconfig(mode); + return true; +} + +void bl_check_replace(const uint8_t *data, size_t len) { + const uint32_t bl_len = flash_area_get_size(&BOOTLOADER_AREA); + const void *bl_data = flash_area_get_address(&BOOTLOADER_AREA, 0, bl_len); + + mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTUPDATE); struct uzlib_uncomp decomp = {0}; uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {0}; @@ -125,6 +109,8 @@ void check_and_replace_bootloader(void) { const image_header *current_bld_hdr = read_image_header(bl_data, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_MAXSIZE); + // todo check sig and contents, as data is now coming from outside + // cannot find valid header for current bootloader, something is wrong ensure(current_bld_hdr == (const image_header *)bl_data ? sectrue : secfalse, "Invalid bootloader header"); @@ -182,7 +168,6 @@ void check_and_replace_bootloader(void) { ensure(flash_lock_write(), NULL); mpu_reconfig(mode); -#endif } #endif diff --git a/core/embed/util/bl_check/inc/util/bl_check.h b/core/embed/util/bl_check/inc/util/bl_check.h index ee4ef277ac..2405087956 100644 --- a/core/embed/util/bl_check/inc/util/bl_check.h +++ b/core/embed/util/bl_check/inc/util/bl_check.h @@ -17,9 +17,33 @@ * along with this program. If not, see . */ -#ifndef __BL_CHECK_H__ -#define __BL_CHECK_H__ +#pragma once -void check_and_replace_bootloader(void); +#include -#endif +/** + * @brief Verify the installed bootloader against expected hashes. + * + * Calculates the hash of the currently installed bootloader and compares + * it against two known-good expected hashes. + * + * @param hash_00 Pointer to the expected hash for 0x00 padded image. + * @param hash_FF Pointer to the expected hash for 0xFF padded image. + * @param hash_len Length of each hash, in bytes. + * + * @return `true` if the installed bootloader's hash does not match either + * of the expected hashes (indicating it should be replaced), + * `false` if it matches one of them. + */ +bool bl_check_check(const uint8_t *hash_00, const uint8_t *hash_FF, + size_t hash_len); + +/** + * @brief Replace the currently installed bootloader. + * + * Writes a new bootloader image into flash. + * + * @param data Pointer to the bootloader image data. + * @param len Size of the bootloader data in bytes. + */ +void bl_check_replace(const uint8_t *data, size_t len);