mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 22:38:08 +00:00
fix(legacy/bootloader): erase storage if going below fix_version
This commit is contained in:
parent
29bab9e8a4
commit
7d93bd3179
1
legacy/bootloader/.changelog.d/noissue.security
Normal file
1
legacy/bootloader/.changelog.d/noissue.security
Normal file
@ -0,0 +1 @@
|
||||
Erase storage when downgrading below fix_version.
|
@ -156,6 +156,51 @@ static secbool readprotobufint(const uint8_t **ptr, uint32_t *result) {
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
/** Reverse-endian version comparison
|
||||
*
|
||||
* Versions are loaded from the header via a packed struct image_header. A
|
||||
* version is represented as a single uint32_t. Arm is natively little-endian,
|
||||
* but the version is actually stored as four bytes in major-minor-patch-build
|
||||
* order. This function implements `cmp` with "lowest" byte first.
|
||||
*/
|
||||
static int version_compare(const uint32_t vera, const uint32_t verb) {
|
||||
int a, b; // signed temp values so that we can safely return a signed result
|
||||
a = vera & 0xFF;
|
||||
b = verb & 0xFF;
|
||||
if (a != b) return a - b;
|
||||
a = (vera >> 8) & 0xFF;
|
||||
b = (verb >> 8) & 0xFF;
|
||||
if (a != b) return a - b;
|
||||
a = (vera >> 16) & 0xFF;
|
||||
b = (verb >> 16) & 0xFF;
|
||||
if (a != b) return a - b;
|
||||
a = (vera >> 24) & 0xFF;
|
||||
b = (verb >> 24) & 0xFF;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static int should_keep_storage(int old_was_signed,
|
||||
uint32_t fix_version_current) {
|
||||
// if the current firmware is unsigned, always erase storage
|
||||
if (SIG_OK != old_was_signed) return SIG_FAIL;
|
||||
|
||||
const image_header *new_hdr = (const image_header *)FW_HEADER;
|
||||
// if the new header is unsigned, erase storage
|
||||
if (SIG_OK != signatures_new_ok(new_hdr, NULL)) return SIG_FAIL;
|
||||
// if the new header hashes don't match flash contents, erase storage
|
||||
if (SIG_OK != check_firmware_hashes(new_hdr)) return SIG_FAIL;
|
||||
|
||||
// going from old-style header to new-style is always an upgrade, keep storage
|
||||
if (firmware_present_old()) return SIG_OK;
|
||||
|
||||
// if the current fix_version is higher than the new one, erase storage
|
||||
if (version_compare(new_hdr->version, fix_version_current) < 0) {
|
||||
return SIG_FAIL;
|
||||
}
|
||||
|
||||
return SIG_OK;
|
||||
}
|
||||
|
||||
static void rx_callback(usbd_device *dev, uint8_t ep) {
|
||||
(void)ep;
|
||||
static uint16_t msg_id = 0xFFFF;
|
||||
@ -163,6 +208,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) {
|
||||
static uint32_t w;
|
||||
static int wi;
|
||||
static int old_was_signed;
|
||||
static uint32_t fix_version_current = 0xffffffff;
|
||||
|
||||
if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return;
|
||||
|
||||
@ -235,10 +281,13 @@ static void rx_callback(usbd_device *dev, uint8_t ep) {
|
||||
(const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
|
||||
old_was_signed =
|
||||
signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr);
|
||||
fix_version_current = hdr->fix_version;
|
||||
} else if (firmware_present_old()) {
|
||||
old_was_signed = signatures_old_ok();
|
||||
fix_version_current = 0;
|
||||
} else {
|
||||
old_was_signed = SIG_FAIL;
|
||||
fix_version_current = 0xffffffff;
|
||||
}
|
||||
erase_code_progress();
|
||||
send_msg_success(dev);
|
||||
@ -388,8 +437,7 @@ static void rx_callback(usbd_device *dev, uint8_t ep) {
|
||||
// 1) old firmware was unsigned or not present
|
||||
// 2) signatures are not OK
|
||||
// 3) hashes are not OK
|
||||
if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) ||
|
||||
SIG_OK != check_firmware_hashes(hdr)) {
|
||||
if (SIG_OK != should_keep_storage(old_was_signed, fix_version_current)) {
|
||||
// erase storage
|
||||
erase_storage();
|
||||
// check erasure
|
||||
|
Loading…
Reference in New Issue
Block a user