From ff3b10a329026decc71668caff972c63cb868f6a Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Fri, 21 Aug 2020 14:58:13 +0200 Subject: [PATCH] legacy/intermediate_fw: Intermediate firmware for T1 (#1084) * legacy/intermediate_fw: skeleton FW with RAM shim function * legacy/intermediate_fw: reboot from RAM * legacy/intermediate_fw: flash erase from RAM * legacy/intermediate_fw: port flash erase body from cm3 * legacy/intermediate_fw: erase works with flash unlock * legacy/intermediate_fw: wait for flash controller ready * legacy/intermediate_fw: cleanup and add comments * legacy/intermediate_fw: disable IRQ before reboot * legacy/intermediate_fw: also erase storage * legacy/intermediate_fw: style * legacy/intermediate_fw: dialogs for update bootloader/erase FW * legacy/intermediate_fw: style * legacy/intermediate_fw: add bootloader replacement code * legacy/intermediate_fw: add CI build script for intermediate FW * legacy/intermediate_fw: call bootloader update * legacy/intermediate_fw: add bootloader update dependency * legacy/intermediate_fw: change setup() at start of main * legacy/intermediate_fw: deduplicate code * docs: table for MEMORY_PROTECT combinations that work on T1 * legacy/intermediate_fw: deduplicate code * legacy/intermediate_fw: check if running in privileged mode * legacy/intermediate_fw: style * legacy/intermediate_fw: ChangeLog * legacy/intermediate_fw: make version match latest bootloader included * legacy/intermediate_fw: style --- docs/legacy/index.md | 18 ++++ legacy/firmware/bl_check.c | 22 +++-- legacy/firmware/bl_check.h | 4 +- legacy/firmware/trezor.c | 2 +- legacy/intermediate_fw/ChangeLog | 28 ++++++ legacy/intermediate_fw/Makefile | 60 +++++++++++++ legacy/intermediate_fw/bl_check.c | 1 + legacy/intermediate_fw/bl_check.h | 1 + legacy/intermediate_fw/bl_data.py | 1 + legacy/intermediate_fw/bootloader.dat | 1 + legacy/intermediate_fw/gettext.h | 1 + legacy/intermediate_fw/header.S | 1 + legacy/intermediate_fw/trezor.c | 125 ++++++++++++++++++++++++++ legacy/intermediate_fw/trezor.h | 40 +++++++++ legacy/intermediate_fw/version.h | 8 ++ legacy/script/cibuild_intermediate_fw | 15 ++++ 16 files changed, 320 insertions(+), 8 deletions(-) create mode 100644 legacy/intermediate_fw/ChangeLog create mode 100644 legacy/intermediate_fw/Makefile create mode 120000 legacy/intermediate_fw/bl_check.c create mode 120000 legacy/intermediate_fw/bl_check.h create mode 120000 legacy/intermediate_fw/bl_data.py create mode 120000 legacy/intermediate_fw/bootloader.dat create mode 120000 legacy/intermediate_fw/gettext.h create mode 120000 legacy/intermediate_fw/header.S create mode 100644 legacy/intermediate_fw/trezor.c create mode 100644 legacy/intermediate_fw/trezor.h create mode 100644 legacy/intermediate_fw/version.h create mode 100755 legacy/script/cibuild_intermediate_fw diff --git a/docs/legacy/index.md b/docs/legacy/index.md index 3d41172521..755db04608 100644 --- a/docs/legacy/index.md +++ b/docs/legacy/index.md @@ -105,3 +105,21 @@ Switch your device to bootloader mode, then execute: ```sh trezorctl firmware-update -f build/legacy/firmware/trezor.bin ``` + +## Combining bootloader and firmware with various `MEMORY_PROTECT` settings, signed/unsigned + +Not all combinations of bootloader and firmware will work. This depends on +3 variables: MEMORY_PROTECT of bootloader, MEMORY_PROTECT of firmware, whether firmware is signed + +This table shows the result for bootloader 1.8.0+ and 1.9.1+: + +| Bootloader MEMORY_PROTECT | Firmware MEMORY_PROTECT | Is firmware officially signed? | Result | +| ------------------------- | ----------------------- | ------------------------------ | ------------------------------------------------------------------------------------------ | +| 1 | 1 | yes | works, official configuration | +| 1 | 1 | no | hardfault in header.S when setting VTOR and stack | +| 0 | 1 | no | works, but don't forget to comment out `check_bootloader`, otherwise it'll get overwritten | +| 0 | 0 | no | hard fault because header.S doesn't set VTOR and stack right | +| 1 | 0 | no | works | + +The other three possibilities with signed firmware and `MEMORY_PROTECT!=0` for bootloader/firmware don't exist. + diff --git a/legacy/firmware/bl_check.c b/legacy/firmware/bl_check.c index 5f55f9abe2..91b79634b8 100644 --- a/legacy/firmware/bl_check.c +++ b/legacy/firmware/bl_check.c @@ -130,7 +130,13 @@ static int known_bootloader(int r, const uint8_t *hash) { } #endif -void check_bootloader(void) { +/** + * If bootloader is older and known, replace with newer bootloader. + * If bootloader is unknown, halt with error message. + * + * @param shutdown_on_success: if true, shuts down device instead of return + */ +void check_bootloader(bool shutdown_on_success) { #if MEMORY_PROTECT uint8_t hash[32] = {0}; int r = memory_bootloader_hash(hash); @@ -178,11 +184,13 @@ void check_bootloader(void) { // check whether the write was OK r = memory_bootloader_hash(hash); if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { - // OK -> show info and halt - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), - _("successfully."), NULL, _("Please reconnect"), - _("the device."), NULL); - shutdown(); + if (shutdown_on_success) { + // OK -> show info and halt + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), + _("successfully."), NULL, _("Please reconnect"), + _("the device."), NULL); + shutdown(); + } return; } } @@ -192,4 +200,6 @@ void check_bootloader(void) { _("contact our support."), NULL); shutdown(); #endif + // prevent compiler warning when MEMORY_PROTECT==0 + (void)shutdown_on_success; } diff --git a/legacy/firmware/bl_check.h b/legacy/firmware/bl_check.h index 5053ca2913..0a4245a0bc 100644 --- a/legacy/firmware/bl_check.h +++ b/legacy/firmware/bl_check.h @@ -20,6 +20,8 @@ #ifndef __BL_CHECK_H__ #define __BL_CHECK_H__ -void check_bootloader(void); +#include + +void check_bootloader(bool shutdown_on_success); #endif diff --git a/legacy/firmware/trezor.c b/legacy/firmware/trezor.c index 22c23cac61..89364ea482 100644 --- a/legacy/firmware/trezor.c +++ b/legacy/firmware/trezor.c @@ -123,7 +123,7 @@ int main(void) { // unpredictable stack protection checks oledInit(); #else - check_bootloader(); + check_bootloader(true); setupApp(); __stack_chk_guard = random32(); // this supports compiler provided // unpredictable stack protection checks diff --git a/legacy/intermediate_fw/ChangeLog b/legacy/intermediate_fw/ChangeLog new file mode 100644 index 0000000000..f03ae9dbad --- /dev/null +++ b/legacy/intermediate_fw/ChangeLog @@ -0,0 +1,28 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Unreleased] + +### Added + +### Deprecated + +### Removed + +### Fixed + +### Security + +------------ + +### Older changelog: + +Version 1.8.0 [Jun 2020] +* Initial version of intermediate firmware +* Updates bootloader to 1.8.0 +* Deletes storage and the intermediate firmware code +* Version of intermediate firmware matches bootloader version included + diff --git a/legacy/intermediate_fw/Makefile b/legacy/intermediate_fw/Makefile new file mode 100644 index 0000000000..8e4876432d --- /dev/null +++ b/legacy/intermediate_fw/Makefile @@ -0,0 +1,60 @@ +APPVER = 1.8.0 + +NAME = trezor + +OBJS += trezor.o +OBJS += header.o +OBJS += bl_check.o +OBJS += ../vendor/trezor-crypto/memzero.o +OBJS += ../vendor/trezor-crypto/sha2.o + +OPTFLAGS ?= -Og + + +../vendor/trezor-crypto/bip32.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/bip39.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/ecdsa.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/sha2.o: OPTFLAGS = -O3 +../vendor/trezor-crypto/secp256k1.o: OPTFLAGS = -O3 + +include ../Makefile.include +CFLAGS:=$(filter-out -fstack-protector-all,$(CFLAGS)) + +DEBUG_LINK ?= 0 +DEBUG_LOG ?= 0 + +CFLAGS += -Wno-sequence-point +CFLAGS += -I../vendor/nanopb -Iprotob -DPB_FIELD_16BIT=1 -DPB_ENCODE_ARRAYS_UNPACKED=1 -DPB_VALIDATE_UTF8=1 +CFLAGS += -DDEBUG_LINK=$(DEBUG_LINK) +CFLAGS += -DDEBUG_LOG=$(DEBUG_LOG) +CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' +CFLAGS += -DUSE_MONERO=0 +ifneq ($(BITCOIN_ONLY),1) +CFLAGS += -DUSE_ETHEREUM=1 +CFLAGS += -DUSE_NEM=1 +MAKO_RENDER_FLAG = +else +CFLAGS += -DUSE_ETHEREUM=0 +CFLAGS += -DUSE_NEM=0 +MAKO_RENDER_FLAG = --bitcoin-only +endif + +%:: %.mako defs + @printf " MAKO $@\n" + $(Q)$(PYTHON) ../vendor/trezor-common/tools/cointool.py render $(MAKO_RENDER_FLAG) $@.mako + +bl_data.h: bl_data.py bootloader.dat + @printf " PYTHON bl_data.py\n" + $(Q)$(PYTHON) bl_data.py + +clean:: + rm -f bl_data.h + find -maxdepth 1 -name "*.mako" | sed 's/.mako$$//' | xargs rm -f + +FIRMWARE_T1_START = 0x08010000 +flash_intermediate_fw: trezor.bin + openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f target/stm32f2x.cfg -c "init; reset halt; flash write_image erase $< $(FIRMWARE_T1_START); exit" + +openocd_reset: + $(OPENOCD) -c "init; reset; exit" + diff --git a/legacy/intermediate_fw/bl_check.c b/legacy/intermediate_fw/bl_check.c new file mode 120000 index 0000000000..ff0ac14655 --- /dev/null +++ b/legacy/intermediate_fw/bl_check.c @@ -0,0 +1 @@ +../firmware/bl_check.c \ No newline at end of file diff --git a/legacy/intermediate_fw/bl_check.h b/legacy/intermediate_fw/bl_check.h new file mode 120000 index 0000000000..f647dcae47 --- /dev/null +++ b/legacy/intermediate_fw/bl_check.h @@ -0,0 +1 @@ +../firmware/bl_check.h \ No newline at end of file diff --git a/legacy/intermediate_fw/bl_data.py b/legacy/intermediate_fw/bl_data.py new file mode 120000 index 0000000000..61419bdcbc --- /dev/null +++ b/legacy/intermediate_fw/bl_data.py @@ -0,0 +1 @@ +../firmware/bl_data.py \ No newline at end of file diff --git a/legacy/intermediate_fw/bootloader.dat b/legacy/intermediate_fw/bootloader.dat new file mode 120000 index 0000000000..8fd9f3b465 --- /dev/null +++ b/legacy/intermediate_fw/bootloader.dat @@ -0,0 +1 @@ +../firmware/bootloader.dat \ No newline at end of file diff --git a/legacy/intermediate_fw/gettext.h b/legacy/intermediate_fw/gettext.h new file mode 120000 index 0000000000..71972d8f88 --- /dev/null +++ b/legacy/intermediate_fw/gettext.h @@ -0,0 +1 @@ +../firmware/gettext.h \ No newline at end of file diff --git a/legacy/intermediate_fw/header.S b/legacy/intermediate_fw/header.S new file mode 120000 index 0000000000..f8d8e98e9d --- /dev/null +++ b/legacy/intermediate_fw/header.S @@ -0,0 +1 @@ +../firmware/header.S \ No newline at end of file diff --git a/legacy/intermediate_fw/trezor.c b/legacy/intermediate_fw/trezor.c new file mode 100644 index 0000000000..199be8fdca --- /dev/null +++ b/legacy/intermediate_fw/trezor.c @@ -0,0 +1,125 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include "trezor.h" +#include +#include +#include +#include "bitmaps.h" +#include "bl_check.h" +#include "layout.h" +#include "memory.h" +#include "memzero.h" +#include "oled.h" +#include "rng.h" +#include "setup.h" +#include "timer.h" +#include "util.h" + +/** Sector erase operation extracted from libopencm3 - flash_erase_sector + * so it can run from RAM + */ +static void __attribute__((noinline, section(".data"))) +erase_sector(uint8_t sector, uint32_t psize) { + // Wait for flash controller to be ready + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY) + ; + // Set program word width + FLASH_CR &= ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT); + FLASH_CR |= psize << FLASH_CR_PROGRAM_SHIFT; + + /* Sector numbering is not contiguous internally! */ + if (sector >= 12) { + sector += 4; + } + + FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT); + FLASH_CR |= (sector & FLASH_CR_SNB_MASK) << FLASH_CR_SNB_SHIFT; + FLASH_CR |= FLASH_CR_SER; + FLASH_CR |= FLASH_CR_STRT; + + // Wait for flash controller to be ready + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY) + ; + FLASH_CR &= ~FLASH_CR_SER; + FLASH_CR &= ~(FLASH_CR_SNB_MASK << FLASH_CR_SNB_SHIFT); +} + +static void __attribute__((noinline, section(".data"))) +erase_firmware_and_storage(void) { + // Flash unlock + FLASH_KEYR = FLASH_KEYR_KEY1; + FLASH_KEYR = FLASH_KEYR_KEY2; + + // Erase storage sectors to prevent firmware downgrade to vulnerable version + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; + i++) { + erase_sector(i, FLASH_CR_PROGRAM_X32); + } + + // Erase firmware sectors + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + erase_sector(i, FLASH_CR_PROGRAM_X32); + } + + // Flash lock + FLASH_CR |= FLASH_CR_LOCK; +} + +void __attribute__((noinline, noreturn, section(".data"))) reboot_device(void) { + __disable_irq(); + SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ; + while (1) + ; +} + +/** Entry point of RAM shim that deletes old FW, storage and reboot */ +void __attribute__((noinline, noreturn, section(".data"))) +erase_fw_and_reboot(void) { + erase_firmware_and_storage(); + reboot_device(); + + for (;;) + ; // never reached, but compiler would generate error +} + +int main(void) { + setupApp(); + __stack_chk_guard = random32(); // this supports compiler provided + // unpredictable stack protection checks + oledInit(); + if (is_mode_unprivileged()) { + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Cannot update", NULL, + NULL, "Unprivileged mode", "Unsigned firmware", NULL); + shutdown(); + } + + mpu_config_off(); // needed for flash writable, RAM RWX + timer_init(); + check_bootloader(false); + + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Erasing old data", NULL, + NULL, "DO NOT UNPLUG", "YOUR TREZOR!", NULL); + oledRefresh(); + + // from this point the execution is from RAM instead of flash + erase_fw_and_reboot(); + + return 0; +} diff --git a/legacy/intermediate_fw/trezor.h b/legacy/intermediate_fw/trezor.h new file mode 100644 index 0000000000..7f2e5e1619 --- /dev/null +++ b/legacy/intermediate_fw/trezor.h @@ -0,0 +1,40 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#ifndef __TREZOR_H__ +#define __TREZOR_H__ + +#include +#include "version.h" + +#define STR(X) #X +#define VERSTR(X) STR(X) + +#ifndef DEBUG_LINK +#define DEBUG_LINK 0 +#endif + +#ifndef DEBUG_LOG +#define DEBUG_LOG 0 +#endif + +/* Screen timeout */ +extern uint32_t system_millis_lock_start; + +#endif diff --git a/legacy/intermediate_fw/version.h b/legacy/intermediate_fw/version.h new file mode 100644 index 0000000000..951e4d7a44 --- /dev/null +++ b/legacy/intermediate_fw/version.h @@ -0,0 +1,8 @@ +// Matches the bootloader version included in this firmware +#define VERSION_MAJOR 1 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 + +#define FIX_VERSION_MAJOR 1 +#define FIX_VERSION_MINOR 8 +#define FIX_VERSION_PATCH 0 diff --git a/legacy/script/cibuild_intermediate_fw b/legacy/script/cibuild_intermediate_fw new file mode 100755 index 0000000000..5a173424f0 --- /dev/null +++ b/legacy/script/cibuild_intermediate_fw @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# script/cibuild_intermediate_fw: +# Setup environment for CI to build intermediate firmware. + +set -e + +cd "$(dirname "$0")/.." + +make -C vendor/libopencm3 lib/stm32/f2 + +make libtrezor.a + +make -C intermediate_fw all sign +