mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-07 15:18:08 +00:00
refactor(core): update bootloader from coreapp, using syscalls (and smcalls)
[no changelog]
This commit is contained in:
parent
f5123c8b3f
commit
9f2dec6169
@ -468,6 +468,7 @@ ALLPATHS = [
|
|||||||
'embed/models',
|
'embed/models',
|
||||||
'embed/gfx/inc',
|
'embed/gfx/inc',
|
||||||
'embed/sys/bsp/inc',
|
'embed/sys/bsp/inc',
|
||||||
|
'embed/util/bl_check/inc',
|
||||||
'embed/util/image/inc',
|
'embed/util/image/inc',
|
||||||
'embed/util/rsod/inc',
|
'embed/util/rsod/inc',
|
||||||
'embed/util/scm_revision/inc',
|
'embed/util/scm_revision/inc',
|
||||||
@ -907,6 +908,16 @@ if 'nrf' in FEATURES_AVAILABLE:
|
|||||||
f'embed/models/{TREZOR_MODEL}/trezor-ble.bin',
|
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)
|
env.Depends(obj_program, qstr_generated)
|
||||||
|
|
||||||
linkerscript_gen = env.Command(
|
linkerscript_gen = env.Command(
|
||||||
|
@ -408,16 +408,6 @@ obj_program.extend(
|
|||||||
' --rename-section .data=.vendorheader,alloc,load,readonly,contents'
|
' --rename-section .data=.vendorheader,alloc,load,readonly,contents'
|
||||||
' $SOURCE $TARGET', ))
|
' $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:
|
if "secmon_layout" in FEATURES_AVAILABLE:
|
||||||
tools.embed_raw_binary(
|
tools.embed_raw_binary(
|
||||||
obj_program,
|
obj_program,
|
||||||
|
@ -361,10 +361,6 @@ cmake_gen = env.Command(
|
|||||||
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
|
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
|
||||||
)
|
)
|
||||||
|
|
||||||
BOOTLOADER_SUFFIX = TREZOR_MODEL
|
|
||||||
if BOOTLOADER_QA:
|
|
||||||
BOOTLOADER_SUFFIX += '_qa'
|
|
||||||
|
|
||||||
# select vendor header
|
# select vendor header
|
||||||
if BOOTLOADER_QA or BOOTLOADER_DEVEL:
|
if BOOTLOADER_QA or BOOTLOADER_DEVEL:
|
||||||
vendor = "dev_DO_NOT_SIGN_signed_dev"
|
vendor = "dev_DO_NOT_SIGN_signed_dev"
|
||||||
@ -389,16 +385,6 @@ obj_program.extend(
|
|||||||
' --rename-section .data=.vendorheader,alloc,load,readonly,contents'
|
' --rename-section .data=.vendorheader,alloc,load,readonly,contents'
|
||||||
' $SOURCE $TARGET', ))
|
' $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(
|
linkerscript_gen = env.Command(
|
||||||
target='memory.ld',
|
target='memory.ld',
|
||||||
source=[f'embed/models/{TREZOR_MODEL}/memory_secmon.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='secmon')],
|
source=[f'embed/models/{TREZOR_MODEL}/memory_secmon.ld', env.get('ENV')['LINKER_SCRIPT'].format(target='secmon')],
|
||||||
|
@ -37,13 +37,33 @@
|
|||||||
#include <sys/linker_utils.h>
|
#include <sys/linker_utils.h>
|
||||||
#include <sys/systask.h>
|
#include <sys/systask.h>
|
||||||
#include <sys/system.h>
|
#include <sys/system.h>
|
||||||
|
#include <util/bl_check.h>
|
||||||
#include <util/rsod.h>
|
#include <util/rsod.h>
|
||||||
#include "rust_ui_common.h"
|
#include "rust_ui_common.h"
|
||||||
|
|
||||||
|
#include <blake2s.h>
|
||||||
|
|
||||||
#ifdef USE_SECP256K1_ZKP
|
#ifdef USE_SECP256K1_ZKP
|
||||||
#include "zkp_context.h"
|
#include "zkp_context.h"
|
||||||
#endif
|
#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
|
#ifdef USE_NRF
|
||||||
#include <io/nrf.h>
|
#include <io/nrf.h>
|
||||||
|
|
||||||
@ -62,14 +82,47 @@ int main_func(uint32_t cmd, void *arg) {
|
|||||||
|
|
||||||
bool fading = DISPLAY_JUMP_BEHAVIOR == DISPLAY_RESET_CONTENT;
|
bool fading = DISPLAY_JUMP_BEHAVIOR == DISPLAY_RESET_CONTENT;
|
||||||
|
|
||||||
#ifdef USE_NRF
|
bool update_required = false;
|
||||||
if (nrf_update_required(&nrf_app_start, (size_t)&nrf_app_size)) {
|
|
||||||
screen_update();
|
#if PRODUCTION || BOOTLOADER_QA
|
||||||
nrf_update(&nrf_app_start, (size_t)&nrf_app_size);
|
|
||||||
fading = true;
|
// 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
|
#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);
|
screen_boot_stage_2(fading);
|
||||||
|
|
||||||
#ifdef USE_SECP256K1_ZKP
|
#ifdef USE_SECP256K1_ZKP
|
||||||
|
@ -157,9 +157,6 @@ void drivers_init() {
|
|||||||
check_oem_keys();
|
check_oem_keys();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PRODUCTION || BOOTLOADER_QA
|
|
||||||
check_and_replace_bootloader();
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BUTTON
|
#ifdef USE_BUTTON
|
||||||
|
@ -77,10 +77,6 @@ static void drivers_init(void) {
|
|||||||
check_oem_keys();
|
check_oem_keys();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PRODUCTION || BOOTLOADER_QA
|
|
||||||
check_and_replace_bootloader();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_OPTIGA
|
#ifdef USE_OPTIGA
|
||||||
optiga_init_and_configure();
|
optiga_init_and_configure();
|
||||||
#endif
|
#endif
|
||||||
|
@ -80,14 +80,7 @@ impl CommonUI for UIBolt {
|
|||||||
show(&mut frame, fade_in);
|
show(&mut frame, fade_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_update() {
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug_overlay")]
|
#[cfg(feature = "ui_debug_overlay")]
|
||||||
fn render_debug_overlay<'s>(_target: &mut impl shape::Renderer<'s>, _info: DebugOverlay) {
|
fn render_debug_overlay<'s>(_target: &mut impl shape::Renderer<'s>, _info: DebugOverlay) {
|
||||||
|
@ -38,9 +38,7 @@ impl CommonUI for UICaesar {
|
|||||||
show(&mut frame, fade_in);
|
show(&mut frame, fade_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_update() {
|
fn screen_update() {}
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug_overlay")]
|
#[cfg(feature = "ui_debug_overlay")]
|
||||||
fn render_debug_overlay<'s>(_target: &mut impl shape::Renderer<'s>, _info: DebugOverlay) {
|
fn render_debug_overlay<'s>(_target: &mut impl shape::Renderer<'s>, _info: DebugOverlay) {
|
||||||
|
@ -86,9 +86,7 @@ impl CommonUI for UIDelizia {
|
|||||||
show(&mut frame, fade_in);
|
show(&mut frame, fade_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn screen_update() {
|
fn screen_update() {}
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug_overlay")]
|
#[cfg(feature = "ui_debug_overlay")]
|
||||||
fn render_debug_overlay<'s>(target: &mut impl shape::Renderer<'s>, info: DebugOverlay) {
|
fn render_debug_overlay<'s>(target: &mut impl shape::Renderer<'s>, info: DebugOverlay) {
|
||||||
|
@ -53,6 +53,8 @@ SECTIONS {
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.bootloader));
|
||||||
|
*(.bootloader*);
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH AT>FLASH
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
@ -44,9 +44,6 @@ SECTIONS {
|
|||||||
*(.text*);
|
*(.text*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
. = ALIGN(4);
|
|
||||||
KEEP(*(.bootloader));
|
|
||||||
*(.bootloader*);
|
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH AT>FLASH
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
@ -44,6 +44,9 @@ SECTIONS {
|
|||||||
*(.text*);
|
*(.text*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.bootloader));
|
||||||
|
*(.bootloader*);
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH AT>FLASH
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
@ -45,9 +45,6 @@ SECTIONS {
|
|||||||
*(.text*);
|
*(.text*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
. = ALIGN(4);
|
|
||||||
KEEP(*(.bootloader));
|
|
||||||
*(.bootloader*);
|
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH AT>FLASH
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
@ -49,6 +49,9 @@ SECTIONS {
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
KEEP(*(.nrf_app));
|
KEEP(*(.nrf_app));
|
||||||
*(.nrf_app*);
|
*(.nrf_app*);
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.bootloader));
|
||||||
|
*(.bootloader*);
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH AT>FLASH
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
@ -49,9 +49,6 @@ SECTIONS {
|
|||||||
*(.text*);
|
*(.text*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
. = ALIGN(4);
|
|
||||||
KEEP(*(.bootloader));
|
|
||||||
*(.bootloader*);
|
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH AT>FLASH
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
@ -55,9 +55,6 @@ SECTIONS {
|
|||||||
*(.text*);
|
*(.text*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
*(.rodata*);
|
*(.rodata*);
|
||||||
. = ALIGN(4);
|
|
||||||
KEEP(*(.bootloader));
|
|
||||||
*(.bootloader*);
|
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
} >FLASH
|
} >FLASH
|
||||||
|
|
||||||
|
@ -49,6 +49,8 @@
|
|||||||
#include <sec/secret.h>
|
#include <sec/secret.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <util/bl_check.h>
|
||||||
|
|
||||||
#include "smcall_numbers.h"
|
#include "smcall_numbers.h"
|
||||||
#include "smcall_probe.h"
|
#include "smcall_probe.h"
|
||||||
#include "smcall_verifiers.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);
|
bootargs_get_args__verified(boot_args);
|
||||||
} break;
|
} 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: {
|
case SMCALL_GET_BOARD_NAME: {
|
||||||
args[0] = get_board_name();
|
args[0] = get_board_name();
|
||||||
} break;
|
} break;
|
||||||
|
@ -33,6 +33,9 @@ typedef enum {
|
|||||||
SMCALL_BOOTARGS_SET = 1,
|
SMCALL_BOOTARGS_SET = 1,
|
||||||
SMCALL_BOOTARGS_GET_ARGS,
|
SMCALL_BOOTARGS_GET_ARGS,
|
||||||
|
|
||||||
|
SMCALL_BL_CHECK_CHECK,
|
||||||
|
SMCALL_BL_CHECK_REPLACE,
|
||||||
|
|
||||||
SMCALL_REBOOT_DEVICE,
|
SMCALL_REBOOT_DEVICE,
|
||||||
SMCALL_REBOOT_TO_BOOTLOADER,
|
SMCALL_REBOOT_TO_BOOTLOADER,
|
||||||
SMCALL_REBOOT_AND_UPGRADE,
|
SMCALL_REBOOT_AND_UPGRADE,
|
||||||
|
@ -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) {
|
void bootargs_get_args(boot_args_t *args) {
|
||||||
smcall_invoke1((uint32_t)args, SMCALL_BOOTARGS_GET_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
|
// board_capabilities.h
|
||||||
|
@ -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]) {
|
void reboot_and_upgrade__verified(const uint8_t hash[32]) {
|
||||||
if (!probe_read_access(hash, 32)) {
|
if (!probe_read_access(hash, 32)) {
|
||||||
goto access_violation;
|
goto access_violation;
|
||||||
|
@ -29,6 +29,15 @@ void bootargs_set__verified(boot_command_t command, const void *args,
|
|||||||
|
|
||||||
void bootargs_get_args__verified(boot_args_t *args);
|
void bootargs_get_args__verified(boot_args_t *args);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <util/bl_check.h>
|
||||||
|
|
||||||
|
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 <sys/bootutils.h>
|
#include <sys/bootutils.h>
|
||||||
|
|
||||||
|
@ -42,6 +42,9 @@ typedef enum {
|
|||||||
|
|
||||||
SYSCALL_SYSEVENTS_POLL,
|
SYSCALL_SYSEVENTS_POLL,
|
||||||
|
|
||||||
|
SYSCALL_BL_CHECK_CHECK,
|
||||||
|
SYSCALL_BL_CHECK_REPLACE,
|
||||||
|
|
||||||
SYSCALL_REBOOT_DEVICE,
|
SYSCALL_REBOOT_DEVICE,
|
||||||
SYSCALL_REBOOT_TO_BOOTLOADER,
|
SYSCALL_REBOOT_TO_BOOTLOADER,
|
||||||
SYSCALL_REBOOT_AND_UPGRADE,
|
SYSCALL_REBOOT_AND_UPGRADE,
|
||||||
|
@ -81,6 +81,10 @@
|
|||||||
#include <io/touch.h>
|
#include <io/touch.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if PRODUCTION || BOOTLOADER_QA
|
||||||
|
#include <util/bl_check.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "syscall_context.h"
|
#include "syscall_context.h"
|
||||||
#include "syscall_internal.h"
|
#include "syscall_internal.h"
|
||||||
#include "syscall_verifiers.h"
|
#include "syscall_verifiers.h"
|
||||||
@ -166,6 +170,19 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
|
|||||||
}
|
}
|
||||||
} break;
|
} 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: {
|
case SYSCALL_REBOOT_DEVICE: {
|
||||||
reboot_device();
|
reboot_device();
|
||||||
} break;
|
} break;
|
||||||
|
@ -84,6 +84,20 @@ void sysevents_poll(const sysevents_t *awaited, sysevents_t *signalled,
|
|||||||
SYSCALL_SYSEVENTS_POLL);
|
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
|
// bootutils.h
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
@ -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) {
|
void system_exit__verified(int exit_code) {
|
||||||
systask_t *task = systask_active();
|
systask_t *task = systask_active();
|
||||||
|
|
||||||
|
@ -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]);
|
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 <util/bl_check.h>
|
||||||
|
void bl_check_replace__verified(const uint8_t *data, size_t len);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
#include <io/display.h>
|
#include <io/display.h>
|
||||||
|
|
||||||
|
@ -30,40 +30,15 @@
|
|||||||
#include "memzero.h"
|
#include "memzero.h"
|
||||||
#include "uzlib.h"
|
#include "uzlib.h"
|
||||||
|
|
||||||
// symbols from bootloader.bin => bootloader.o
|
static secbool hash_match(const uint8_t *hash, const uint8_t *hash_00,
|
||||||
extern const void _deflated_bootloader_start;
|
const uint8_t *hash_FF) {
|
||||||
extern const void _deflated_bootloader_size;
|
if (0 == memcmp(hash, hash_00, BLAKE2S_DIGEST_LENGTH)) return sectrue;
|
||||||
|
if (0 == memcmp(hash, hash_FF, BLAKE2S_DIGEST_LENGTH)) return sectrue;
|
||||||
#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;
|
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#define UZLIB_WINDOW_SIZE (1 << 10)
|
#define UZLIB_WINDOW_SIZE (1 << 10)
|
||||||
|
|
||||||
#if PRODUCTION || BOOTLOADER_QA
|
|
||||||
static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window,
|
static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window,
|
||||||
const void *src, uint32_t srcsize, void *dest,
|
const void *src, uint32_t srcsize, void *dest,
|
||||||
uint32_t destsize) {
|
uint32_t destsize) {
|
||||||
@ -78,12 +53,15 @@ static void uzlib_prepare(struct uzlib_uncomp *decomp, uint8_t *window,
|
|||||||
decomp->dest_limit = decomp->dest + destsize;
|
decomp->dest_limit = decomp->dest + destsize;
|
||||||
uzlib_uncompress_init(decomp, window, window ? UZLIB_WINDOW_SIZE : 0);
|
uzlib_uncompress_init(decomp, window, window ? UZLIB_WINDOW_SIZE : 0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void check_and_replace_bootloader(void) {
|
bool bl_check_check(const uint8_t *hash_00, const uint8_t *hash_FF,
|
||||||
#if PRODUCTION || BOOTLOADER_QA
|
size_t hash_len) {
|
||||||
mpu_mode_t mode = mpu_reconfig(MPU_MODE_BOOTUPDATE);
|
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
|
// compute current bootloader hash
|
||||||
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
|
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
|
||||||
const uint32_t bl_len = flash_area_get_size(&BOOTLOADER_AREA);
|
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
|
// ensure(known_bootloader(hash, BLAKE2S_DIGEST_LENGTH), "Unknown bootloader
|
||||||
// detected");
|
// detected");
|
||||||
|
|
||||||
// do we have the latest bootloader?
|
// does the bootloader match?
|
||||||
if (sectrue == latest_bootloader(hash, BLAKE2S_DIGEST_LENGTH)) {
|
if (sectrue == hash_match(hash, hash_00, hash_FF)) {
|
||||||
mpu_reconfig(mode);
|
mpu_reconfig(mode);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace bootloader with the latest one
|
mpu_reconfig(mode);
|
||||||
const uint32_t *data = (const uint32_t *)&_deflated_bootloader_start;
|
return true;
|
||||||
const uint32_t len = (const uint32_t)&_deflated_bootloader_size;
|
}
|
||||||
|
|
||||||
|
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};
|
struct uzlib_uncomp decomp = {0};
|
||||||
uint8_t decomp_window[UZLIB_WINDOW_SIZE] = {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 =
|
const image_header *current_bld_hdr =
|
||||||
read_image_header(bl_data, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_MAXSIZE);
|
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
|
// cannot find valid header for current bootloader, something is wrong
|
||||||
ensure(current_bld_hdr == (const image_header *)bl_data ? sectrue : secfalse,
|
ensure(current_bld_hdr == (const image_header *)bl_data ? sectrue : secfalse,
|
||||||
"Invalid bootloader header");
|
"Invalid bootloader header");
|
||||||
@ -182,7 +168,6 @@ void check_and_replace_bootloader(void) {
|
|||||||
ensure(flash_lock_write(), NULL);
|
ensure(flash_lock_write(), NULL);
|
||||||
|
|
||||||
mpu_reconfig(mode);
|
mpu_reconfig(mode);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,9 +17,33 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __BL_CHECK_H__
|
#pragma once
|
||||||
#define __BL_CHECK_H__
|
|
||||||
|
|
||||||
void check_and_replace_bootloader(void);
|
#include <trezor_types.h>
|
||||||
|
|
||||||
#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);
|
||||||
|
Loading…
Reference in New Issue
Block a user