diff --git a/docs/legacy/index.md b/docs/legacy/index.md index 3d4117252..755db0460 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 5f55f9abe..91b79634b 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 5053ca291..0a4245a0b 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 22c23cac6..89364ea48 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 000000000..f03ae9dba --- /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 000000000..8e4876432 --- /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 000000000..ff0ac1465 --- /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 000000000..f647dcae4 --- /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 000000000..61419bdcb --- /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 000000000..8fd9f3b46 --- /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 000000000..71972d8f8 --- /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 000000000..f8d8e98e9 --- /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 000000000..199be8fdc --- /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 000000000..7f2e5e161 --- /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 000000000..951e4d7a4 --- /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 000000000..5a173424f --- /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 +