mirror of https://github.com/wolfSSL/wolfBoot.git
Merge pull request #463 from jpbland1/bad-image-recovery
add emergency fallback test, currently fails due topull/408/head
commit
b9dc7eee46
|
@ -51,6 +51,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-internal-flash-with-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
|
||||
# TEST with NVM_WRITEONCE enabled
|
||||
- name: make clean
|
||||
|
@ -89,6 +97,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-internal-flash-with-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
|
||||
# TEST with NVM_WRITEONCE AND FLAGS_HOME enabled
|
||||
- name: make clean
|
||||
|
@ -127,6 +143,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-internal-flash-with-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
|
||||
# TEST with NVM_WRITEONCE AND FLAGS_HOME AND FLAGS_INVERT enabled
|
||||
- name: make clean
|
||||
|
@ -165,6 +189,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-external-flash-with-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
|
||||
# TEST with DELTA updates
|
||||
- name: make clean
|
||||
|
@ -189,7 +221,7 @@ jobs:
|
|||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make test-sim-internal-flash-with-delta-update
|
||||
make clean && make test-sim-internal-flash-with-delta-update
|
||||
|
||||
- name: Run update-revert test (DELTA)
|
||||
run: |
|
||||
|
@ -197,7 +229,7 @@ jobs:
|
|||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make test-sim-internal-flash-with-delta-update
|
||||
make clean && make test-sim-internal-flash-with-delta-update
|
||||
|
||||
- name: Run update-revert test with power failures (DELTA)
|
||||
run: |
|
||||
|
@ -248,6 +280,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-external-flash-with-enc-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
# TEST with encryption (aes128) and delta updates
|
||||
- name: make clean
|
||||
run: |
|
||||
|
@ -322,6 +362,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-external-flash-with-enc-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
# TEST with encryption (aes128) and NVM_WRITEONCE and FLAGS_HOME
|
||||
|
||||
- name: make clean
|
||||
|
@ -355,6 +403,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-external-flash-with-enc-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
# TEST with encryption (aes128) and NVM_WRITEONCE and FLAGS_HOME and FLAGS_INVERT
|
||||
|
||||
- name: make clean
|
||||
|
@ -388,6 +444,14 @@ jobs:
|
|||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume.sh
|
||||
|
||||
- name: Rebuild wolfboot.elf
|
||||
run: |
|
||||
make clean && make test-sim-external-flash-with-enc-update
|
||||
|
||||
- name: Run emergency fallback test
|
||||
run: |
|
||||
tools/scripts/sim-update-emergency-fallback.sh
|
||||
|
||||
# TEST with encryption (aes128) and NVM_WRITEONCE and DELTA updates
|
||||
- name: make clean
|
||||
run: |
|
||||
|
@ -451,6 +515,7 @@ jobs:
|
|||
- name: Run update test with DISABLE_BACKUP and powefail
|
||||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume-nobackup.sh
|
||||
|
||||
# TEST with backup disabled + NVM_WRITEONCE
|
||||
- name: make clean
|
||||
run: |
|
||||
|
@ -478,6 +543,7 @@ jobs:
|
|||
- name: Run update test with DISABLE_BACKUP and powefail
|
||||
run: |
|
||||
tools/scripts/sim-update-powerfail-resume-nobackup.sh
|
||||
|
||||
# TEST with backup disabled + FLAGS_HOME
|
||||
- name: make clean
|
||||
run: |
|
||||
|
|
31
hal/sim.c
31
hal/sim.c
|
@ -45,6 +45,7 @@
|
|||
uint8_t *sim_ram_base;
|
||||
static uint8_t *flash_base;
|
||||
|
||||
int forceEmergency = 0;
|
||||
uint32_t erasefail_address = 0xFFFFFFFF;
|
||||
|
||||
#define INTERNAL_FLASH_FILE "./internal_flash.dd"
|
||||
|
@ -105,8 +106,29 @@ void hal_prepare_boot(void)
|
|||
|
||||
int hal_flash_write(uintptr_t address, const uint8_t *data, int len)
|
||||
{
|
||||
/* implicit cast abide compiler warning */
|
||||
memcpy((void*)address, data, len);
|
||||
int i;
|
||||
if (forceEmergency == 1 && address == WOLFBOOT_PARTITION_BOOT_ADDRESS) {
|
||||
/* implicit cast abide compiler warning */
|
||||
memset((void*)address, 0, len);
|
||||
/* let the rest of the writes work properly for the emergency update */
|
||||
forceEmergency = 0;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < len; i++) {
|
||||
#ifdef NVM_FLASH_WRITEONCE
|
||||
if (((uint8_t*)address)[i] != FLASH_BYTE_ERASED) {
|
||||
/* no writing to non-erased page in NVM_FLASH_WRITEONCE */
|
||||
printf("NVM_FLASH_WRITEONCE non-erased write detected!\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
#ifdef WOLFBOOT_FLAGS_INVERT
|
||||
((uint8_t*)address)[i] |= data[i];
|
||||
#else
|
||||
((uint8_t*)address)[i] &= data[i];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -150,8 +172,11 @@ void hal_init(void)
|
|||
erasefail_address = strtol(main_argv[++i], NULL, 16);
|
||||
fprintf(stderr, "Set power fail to erase at address %x\n",
|
||||
erasefail_address);
|
||||
break;
|
||||
}
|
||||
/* force a bad write of the boot partition to trigger and test the
|
||||
* emergency fallback feature */
|
||||
else if (strcmp(main_argv[i], "emergency") == 0)
|
||||
forceEmergency = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -257,7 +257,9 @@ extern "C" {
|
|||
#ifndef WOLFBOOT_FLAGS_INVERT
|
||||
#define IMG_STATE_NEW 0xFF
|
||||
#define IMG_STATE_UPDATING 0x70
|
||||
#define IMG_STATE_FINAL_FLAGS 0x30
|
||||
/* now just an intermediary state, update state will always be either new or
|
||||
* updating before the application boots*/
|
||||
#define IMG_STATE_FINAL_FLAGS 0x30
|
||||
#define IMG_STATE_TESTING 0x10
|
||||
#define IMG_STATE_SUCCESS 0x00
|
||||
#define FLASH_BYTE_ERASED 0xFF
|
||||
|
@ -265,8 +267,8 @@ extern "C" {
|
|||
#else
|
||||
#define IMG_STATE_NEW 0x00
|
||||
#define IMG_STATE_UPDATING 0x8F
|
||||
#define IMG_STATE_FINAL_FLAGS 0xBF
|
||||
#define IMG_STATE_TESTING 0xEF
|
||||
#define IMG_STATE_FINAL_FLAGS 0xBF
|
||||
#define IMG_STATE_SUCCESS 0xFF
|
||||
#define FLASH_BYTE_ERASED 0x00
|
||||
#define FLASH_WORD_ERASED 0x00000000UL
|
||||
|
|
30
src/image.c
30
src/image.c
|
@ -611,8 +611,6 @@ static int image_sha256(struct wolfBoot_image *img, uint8_t *hash)
|
|||
*/
|
||||
static void key_sha256(uint8_t key_slot, uint8_t *hash)
|
||||
{
|
||||
int blksz;
|
||||
unsigned int i = 0;
|
||||
uint8_t *pubkey = keystore_get_buffer(key_slot);
|
||||
int pubkey_sz = keystore_get_size(key_slot);
|
||||
wc_Sha256 sha256_ctx;
|
||||
|
@ -621,13 +619,7 @@ static void key_sha256(uint8_t key_slot, uint8_t *hash)
|
|||
return;
|
||||
|
||||
wc_InitSha256(&sha256_ctx);
|
||||
while (i < (uint32_t)pubkey_sz) {
|
||||
blksz = WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
if ((i + blksz) > (uint32_t)pubkey_sz)
|
||||
blksz = pubkey_sz - i;
|
||||
wc_Sha256Update(&sha256_ctx, (pubkey + i), blksz);
|
||||
i += blksz;
|
||||
}
|
||||
wc_Sha256Update(&sha256_ctx, pubkey, (word32)pubkey_sz);
|
||||
wc_Sha256Final(&sha256_ctx, hash);
|
||||
}
|
||||
#endif /* WOLFBOOT_NO_SIGN */
|
||||
|
@ -700,8 +692,6 @@ static int image_sha384(struct wolfBoot_image *img, uint8_t *hash)
|
|||
*/
|
||||
static void key_sha384(uint8_t key_slot, uint8_t *hash)
|
||||
{
|
||||
int blksz;
|
||||
unsigned int i = 0;
|
||||
uint8_t *pubkey = keystore_get_buffer(key_slot);
|
||||
int pubkey_sz = keystore_get_size(key_slot);
|
||||
wc_Sha384 sha384_ctx;
|
||||
|
@ -710,13 +700,7 @@ static void key_sha384(uint8_t key_slot, uint8_t *hash)
|
|||
return;
|
||||
|
||||
wc_InitSha384(&sha384_ctx);
|
||||
while (i < (uint32_t)(pubkey_sz)) {
|
||||
blksz = WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
if ((i + blksz) > (uint32_t)pubkey_sz)
|
||||
blksz = pubkey_sz - i;
|
||||
wc_Sha384Update(&sha384_ctx, (pubkey + i), blksz);
|
||||
i += blksz;
|
||||
}
|
||||
wc_Sha384Update(&sha384_ctx, pubkey, (word32)pubkey_sz);
|
||||
wc_Sha384Final(&sha384_ctx, hash);
|
||||
}
|
||||
#endif /* WOLFBOOT_NO_SIGN */
|
||||
|
@ -789,8 +773,6 @@ static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash)
|
|||
*/
|
||||
static void key_sha3_384(uint8_t key_slot, uint8_t *hash)
|
||||
{
|
||||
int blksz;
|
||||
unsigned int i = 0;
|
||||
uint8_t *pubkey = keystore_get_buffer(key_slot);
|
||||
int pubkey_sz = keystore_get_size(key_slot);
|
||||
wc_Sha3 sha3_ctx;
|
||||
|
@ -798,13 +780,7 @@ static void key_sha3_384(uint8_t key_slot, uint8_t *hash)
|
|||
if (!pubkey || (pubkey_sz < 0))
|
||||
return;
|
||||
wc_InitSha3_384(&sha3_ctx, NULL, INVALID_DEVID);
|
||||
while (i < (uint32_t)pubkey_sz) {
|
||||
blksz = WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
if ((i + blksz) > (uint32_t)pubkey_sz)
|
||||
blksz = pubkey_sz - i;
|
||||
wc_Sha3_384_Update(&sha3_ctx, pubkey + i, blksz);
|
||||
i += blksz;
|
||||
}
|
||||
wc_Sha3_384_Update(&sha3_ctx, pubkey, (word32)pubkey_sz);
|
||||
wc_Sha3_384_Final(&sha3_ctx, hash);
|
||||
}
|
||||
#endif /* WOLFBOOT_NO_SIGN */
|
||||
|
|
|
@ -350,12 +350,8 @@ static int RAMFUNCTION trailer_write(uint8_t part, uintptr_t addr, uint8_t val)
|
|||
/* Calculate write address */
|
||||
addr_write = addr_align - ((!nvm_cached_sector) * NVM_CACHE_SIZE);
|
||||
|
||||
/* Ensure that the destination was erased, or force erase */
|
||||
if (*((uint32_t *)(addr_write + NVM_CACHE_SIZE - sizeof(uint32_t)))
|
||||
!= FLASH_WORD_ERASED)
|
||||
{
|
||||
hal_flash_erase(addr_write, NVM_CACHE_SIZE);
|
||||
}
|
||||
/* Ensure that the destination was erased */
|
||||
hal_flash_erase(addr_write, NVM_CACHE_SIZE);
|
||||
#if FLASHBUFFER_SIZE != WOLFBOOT_SECTOR_SIZE
|
||||
addr_off = 0;
|
||||
while ((addr_off < WOLFBOOT_SECTOR_SIZE) && (ret == 0)) {
|
||||
|
@ -718,17 +714,21 @@ void RAMFUNCTION wolfBoot_erase_partition(uint8_t part)
|
|||
uint32_t address = 0;
|
||||
int size = 0;
|
||||
|
||||
if (part == PART_BOOT) {
|
||||
address = (uint32_t)WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
size = WOLFBOOT_PARTITION_SIZE;
|
||||
}
|
||||
if (part == PART_UPDATE) {
|
||||
address = (uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
|
||||
size = WOLFBOOT_PARTITION_SIZE;
|
||||
}
|
||||
if (part == PART_SWAP) {
|
||||
address = (uint32_t)WOLFBOOT_PARTITION_SWAP_ADDRESS;
|
||||
size = WOLFBOOT_SECTOR_SIZE;
|
||||
switch (part) {
|
||||
case PART_BOOT:
|
||||
address = (uint32_t)WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
size = WOLFBOOT_PARTITION_SIZE;
|
||||
break;
|
||||
case PART_UPDATE:
|
||||
address = (uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
|
||||
size = WOLFBOOT_PARTITION_SIZE;
|
||||
break;
|
||||
case PART_SWAP:
|
||||
address = (uint32_t)WOLFBOOT_PARTITION_SWAP_ADDRESS;
|
||||
size = WOLFBOOT_SECTOR_SIZE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
|
@ -819,16 +819,10 @@ void RAMFUNCTION wolfBoot_success(void)
|
|||
if (FLAGS_BOOT_EXT()) {
|
||||
ext_flash_unlock();
|
||||
wolfBoot_set_partition_state(PART_BOOT, st);
|
||||
/* set update so IMG_STATE_FINAL_FLAGS isn't triggering pointless calls
|
||||
* to wolfBoot update */
|
||||
wolfBoot_set_partition_state(PART_UPDATE, st);
|
||||
ext_flash_lock();
|
||||
} else {
|
||||
hal_flash_unlock();
|
||||
wolfBoot_set_partition_state(PART_BOOT, st);
|
||||
/* set update so IMG_STATE_FINAL_FLAGS isn't triggering pointless calls
|
||||
* to wolfBoot update */
|
||||
wolfBoot_set_partition_state(PART_UPDATE, st);
|
||||
hal_flash_lock();
|
||||
}
|
||||
#ifdef EXT_ENCRYPTED
|
||||
|
@ -866,13 +860,9 @@ uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
|
|||
unit_dbg("Explicit end of options reached\n");
|
||||
break;
|
||||
}
|
||||
if (*p == HDR_PADDING) {
|
||||
/* Padding byte (skip one position) */
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
/* Sanity check to prevent dereferencing unaligned half-words */
|
||||
if ((((size_t)p) & 0x01) != 0) {
|
||||
/* Sanity check to prevent dereferencing unaligned half-words and skip
|
||||
* past padding bytes */
|
||||
if ((*p == HDR_PADDING) || ((((size_t)p) & 0x01) != 0)) {
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -194,6 +194,93 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
|
|||
return pos;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_BACKUP
|
||||
static int wolfBoot_swap_and_final_erase(int resume)
|
||||
{
|
||||
struct wolfBoot_image boot[1];
|
||||
struct wolfBoot_image update[1];
|
||||
struct wolfBoot_image swap[1];
|
||||
uint8_t st;
|
||||
int eraseLen = WOLFBOOT_SECTOR_SIZE
|
||||
#ifdef NVM_FLASH_WRITEONCE
|
||||
/* need to erase the redundant sector too */
|
||||
* 2
|
||||
#endif
|
||||
;
|
||||
int swapDone = 0;
|
||||
uintptr_t tmpBootPos = WOLFBOOT_PARTITION_SIZE - eraseLen -
|
||||
WOLFBOOT_SECTOR_SIZE;
|
||||
/* final swap and erase flag is WOLFBOOT_MAGIC_TRAIL */
|
||||
uint8_t tmpBuffer[sizeof(WOLFBOOT_MAGIC_TRAIL)
|
||||
#ifdef EXT_ENCRYPTED
|
||||
+ ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE
|
||||
#endif
|
||||
];
|
||||
/* open boot */
|
||||
wolfBoot_open_image(boot, PART_BOOT);
|
||||
/* open update */
|
||||
wolfBoot_open_image(update, PART_UPDATE);
|
||||
/* open swap */
|
||||
wolfBoot_open_image(swap, PART_SWAP);
|
||||
wolfBoot_get_partition_state(PART_UPDATE, &st);
|
||||
/* read from tmpBootPos */
|
||||
memcpy((void*)tmpBuffer, (void*)(boot->hdr + tmpBootPos),
|
||||
sizeof(tmpBuffer));
|
||||
/* check for TRAIL */
|
||||
#ifdef EXT_ENCRYPTED
|
||||
if (*(uint32_t*)(tmpBuffer + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE) ==
|
||||
WOLFBOOT_MAGIC_TRAIL) {
|
||||
swapDone = 1;
|
||||
}
|
||||
#else
|
||||
if (((uint32_t*)tmpBuffer)[0] == WOLFBOOT_MAGIC_TRAIL) {
|
||||
swapDone = 1;
|
||||
}
|
||||
#endif
|
||||
/* if resuming, quit if swap isn't done */
|
||||
if ((resume == 1) && (swapDone == 0) && (st != IMG_STATE_FINAL_FLAGS))
|
||||
return -1;
|
||||
if (swapDone == 0) {
|
||||
/* IMG_STATE_FINAL_FLAGS allows re-entry without blowing away swap */
|
||||
if (st != IMG_STATE_FINAL_FLAGS) {
|
||||
/* store the sector at tmpBootPos into swap */
|
||||
wolfBoot_copy_sector(boot, swap, tmpBootPos / WOLFBOOT_SECTOR_SIZE);
|
||||
/* set FINAL_SWAP for re-entry */
|
||||
wolfBoot_set_partition_state(PART_UPDATE, IMG_STATE_FINAL_FLAGS);
|
||||
}
|
||||
#ifdef EXT_ENCRYPTED
|
||||
/* get encryption key and iv if encryption is enabled */
|
||||
wolfBoot_get_encrypt_key(tmpBuffer, tmpBuffer + ENCRYPT_KEY_SIZE);
|
||||
#endif
|
||||
/* write TRAIL, encryption key and iv if enabled to tmpBootPos*/
|
||||
#ifdef EXT_ENCRYPTED
|
||||
*(uint32_t*)(tmpBuffer + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE)
|
||||
= WOLFBOOT_MAGIC_TRAIL;
|
||||
#else
|
||||
((uint32_t*)tmpBuffer)[0] = WOLFBOOT_MAGIC_TRAIL;
|
||||
#endif
|
||||
wb_flash_erase(boot, tmpBootPos, WOLFBOOT_SECTOR_SIZE);
|
||||
wb_flash_write(boot, tmpBootPos, (void*)tmpBuffer, sizeof(tmpBuffer));
|
||||
}
|
||||
/* erase the last boot sector(s) */
|
||||
wb_flash_erase(boot, WOLFBOOT_PARTITION_SIZE - eraseLen, eraseLen);
|
||||
/* set the encryption key */
|
||||
#ifdef EXT_ENCRYPTED
|
||||
wolfBoot_set_encrypt_key(tmpBuffer, tmpBuffer + ENCRYPT_KEY_SIZE);
|
||||
#endif
|
||||
/* write the original contents of tmpBootPos back */
|
||||
if (tmpBootPos < boot->fw_size + IMAGE_HEADER_SIZE)
|
||||
wolfBoot_copy_sector(swap, boot, tmpBootPos / WOLFBOOT_SECTOR_SIZE);
|
||||
else
|
||||
wb_flash_erase(boot, tmpBootPos, WOLFBOOT_SECTOR_SIZE);
|
||||
/* mark boot as TESTING */
|
||||
wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING);
|
||||
/* erase the last sector(s) of update */
|
||||
wb_flash_erase(update, WOLFBOOT_PARTITION_SIZE - eraseLen, eraseLen);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DELTA_UPDATES
|
||||
|
||||
#ifndef DELTA_BLOCK_SIZE
|
||||
|
@ -202,7 +289,7 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
|
|||
|
||||
static int wolfBoot_delta_update(struct wolfBoot_image *boot,
|
||||
struct wolfBoot_image *update, struct wolfBoot_image *swap, int inverse,
|
||||
int resume_inverse)
|
||||
int resume)
|
||||
{
|
||||
int sector = 0;
|
||||
int ret;
|
||||
|
@ -242,14 +329,14 @@ static int wolfBoot_delta_update(struct wolfBoot_image *boot,
|
|||
upd_v = wolfBoot_update_firmware_version();
|
||||
delta_base_v = wolfBoot_get_diffbase_version(PART_UPDATE);
|
||||
if (inverse) {
|
||||
if (((cur_v == upd_v) && (delta_base_v < cur_v)) || resume_inverse) {
|
||||
if (((cur_v == upd_v) && (delta_base_v < cur_v)) || resume) {
|
||||
ret = wb_patch_init(&ctx, boot->hdr, boot->fw_size +
|
||||
IMAGE_HEADER_SIZE, update->hdr + *img_offset, *img_size);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
if (!resume_inverse && (cur_v != delta_base_v)) {
|
||||
if (!resume && (cur_v != delta_base_v)) {
|
||||
/* Wrong base image, cannot apply delta patch */
|
||||
ret = -1;
|
||||
} else {
|
||||
|
@ -346,14 +433,10 @@ static int wolfBoot_delta_update(struct wolfBoot_image *boot,
|
|||
wb_flash_erase(boot, sector * WOLFBOOT_SECTOR_SIZE, WOLFBOOT_SECTOR_SIZE);
|
||||
sector++;
|
||||
}
|
||||
/* mark that our sector flags aren't reliable in testing mode */
|
||||
st = IMG_STATE_FINAL_FLAGS;
|
||||
wolfBoot_set_partition_state(PART_UPDATE, st);
|
||||
/* mark boot partition as testing */
|
||||
st = IMG_STATE_TESTING;
|
||||
wolfBoot_set_partition_state(PART_BOOT, st);
|
||||
/* start re-entrant final erase, return code is only for resumption in
|
||||
* wolfBoot_start*/
|
||||
wolfBoot_swap_and_final_erase(0);
|
||||
out:
|
||||
wb_flash_erase(swap, 0, WOLFBOOT_SECTOR_SIZE);
|
||||
#ifdef EXT_FLASH
|
||||
ext_flash_lock();
|
||||
#endif
|
||||
|
@ -377,7 +460,7 @@ out:
|
|||
#define MAX_UPDATE_SIZE (size_t)((WOLFBOOT_PARTITION_SIZE - (2 *WOLFBOOT_SECTOR_SIZE)))
|
||||
#endif
|
||||
|
||||
static inline int wolfBoot_get_total_size(struct wolfBoot_image* boot,
|
||||
static int wolfBoot_get_total_size(struct wolfBoot_image* boot,
|
||||
struct wolfBoot_image* update)
|
||||
{
|
||||
uint32_t total_size = 0;
|
||||
|
@ -392,20 +475,28 @@ static inline int wolfBoot_get_total_size(struct wolfBoot_image* boot,
|
|||
|
||||
static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
||||
{
|
||||
int flagRet;
|
||||
uint32_t total_size = 0;
|
||||
const uint32_t sector_size = WOLFBOOT_SECTOR_SIZE;
|
||||
uint32_t sector = 0;
|
||||
uint8_t flag, st;
|
||||
/* we need to pre-set flag to SECT_FLAG_NEW in case magic hasn't been set
|
||||
* on the update partion as part of the delta update direction check. if
|
||||
* magic has not been set flag will have an un-determined value when we go
|
||||
* to check it */
|
||||
uint8_t flag = SECT_FLAG_NEW;
|
||||
uint8_t st;
|
||||
struct wolfBoot_image boot, update, swap;
|
||||
uint16_t update_type;
|
||||
uint32_t fw_size;
|
||||
uint32_t size;
|
||||
#if defined(DISABLE_BACKUP) && defined(EXT_ENCRYPTED)
|
||||
uint8_t key[ENCRYPT_KEY_SIZE];
|
||||
uint8_t nonce[ENCRYPT_NONCE_SIZE];
|
||||
#endif
|
||||
#ifdef DELTA_UPDATES
|
||||
int inverse = 0;
|
||||
int inverse_resume = 0;
|
||||
int resume = 0;
|
||||
int stateRet = -1;
|
||||
uint32_t cur_v;
|
||||
uint32_t up_v;
|
||||
#endif
|
||||
|
@ -427,10 +518,9 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
|
||||
update_type = wolfBoot_get_image_type(PART_UPDATE);
|
||||
|
||||
wolfBoot_get_update_sector_flag(0, &flag);
|
||||
/* Check the first sector to detect interrupted update */
|
||||
if ((wolfBoot_get_update_sector_flag(0, &flag) < 0) ||
|
||||
(flag == SECT_FLAG_NEW))
|
||||
{
|
||||
if (flag == SECT_FLAG_NEW) {
|
||||
if (((update_type & 0x000F) != HDR_IMG_TYPE_APP) ||
|
||||
((update_type & 0xFF00) != HDR_IMG_TYPE_AUTH))
|
||||
return -1;
|
||||
|
@ -458,20 +548,31 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
cur_v = wolfBoot_current_firmware_version();
|
||||
up_v = wolfBoot_update_firmware_version();
|
||||
inverse = cur_v >= up_v;
|
||||
/* if magic isn't set stateRet will be -1 but that means we're on a
|
||||
* fresh partition and aren't resuming */
|
||||
stateRet = wolfBoot_get_partition_state(PART_UPDATE, &st);
|
||||
|
||||
/* if the first sector flag is not new but we are updating then */
|
||||
/* we were interrupted */
|
||||
if (flag != SECT_FLAG_NEW &&
|
||||
wolfBoot_get_partition_state(PART_UPDATE, &st) == 0 &&
|
||||
st == IMG_STATE_UPDATING) {
|
||||
if ((cur_v == 0) || (cur_v == up_v)) {
|
||||
/* if we've already written a sector or we've mangled the boot partition
|
||||
* header we can't determine the direction by version numbers. instead
|
||||
* use the update partition state, updating means regular, new means
|
||||
* reverting */
|
||||
if ((stateRet == 0) && ((flag != SECT_FLAG_NEW) || (cur_v == 0))) {
|
||||
resume = 1;
|
||||
if (st == IMG_STATE_UPDATING) {
|
||||
inverse = 0;
|
||||
}
|
||||
else {
|
||||
inverse = 1;
|
||||
inverse_resume = 1;
|
||||
}
|
||||
}
|
||||
/* If we're dealing with a "ping-pong" fallback that wasn't interrupted
|
||||
* we need to set to UPDATING, otherwise there's no way to tell the
|
||||
* original direction of the update once interrupted */
|
||||
else if ((inverse == 0) && (fallback_allowed == 1)) {
|
||||
wolfBoot_set_partition_state(PART_UPDATE, IMG_STATE_UPDATING);
|
||||
}
|
||||
|
||||
return wolfBoot_delta_update(&boot, &update, &swap, inverse,
|
||||
inverse_resume);
|
||||
return wolfBoot_delta_update(&boot, &update, &swap, inverse, resume);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -486,29 +587,37 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
* If something goes wrong, the operation will be resumed upon reboot.
|
||||
*/
|
||||
while ((sector * sector_size) < total_size) {
|
||||
if ((wolfBoot_get_update_sector_flag(sector, &flag) != 0) || (flag == SECT_FLAG_NEW)) {
|
||||
flag = SECT_FLAG_SWAPPING;
|
||||
wolfBoot_copy_sector(&update, &swap, sector);
|
||||
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
|
||||
wolfBoot_set_update_sector_flag(sector, flag);
|
||||
}
|
||||
if (flag == SECT_FLAG_SWAPPING) {
|
||||
uint32_t size = total_size - (sector * sector_size);
|
||||
if (size > sector_size)
|
||||
size = sector_size;
|
||||
flag = SECT_FLAG_BACKUP;
|
||||
wolfBoot_copy_sector(&boot, &update, sector);
|
||||
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
|
||||
wolfBoot_set_update_sector_flag(sector, flag);
|
||||
}
|
||||
if (flag == SECT_FLAG_BACKUP) {
|
||||
uint32_t size = total_size - (sector * sector_size);
|
||||
if (size > sector_size)
|
||||
size = sector_size;
|
||||
flag = SECT_FLAG_UPDATED;
|
||||
wolfBoot_copy_sector(&swap, &boot, sector);
|
||||
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
|
||||
wolfBoot_set_update_sector_flag(sector, flag);
|
||||
flag = SECT_FLAG_NEW;
|
||||
wolfBoot_get_update_sector_flag(sector, &flag);
|
||||
switch (flag) {
|
||||
case SECT_FLAG_NEW:
|
||||
flag = SECT_FLAG_SWAPPING;
|
||||
wolfBoot_copy_sector(&update, &swap, sector);
|
||||
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
|
||||
wolfBoot_set_update_sector_flag(sector, flag);
|
||||
/* FALL THROUGH */
|
||||
case SECT_FLAG_SWAPPING:
|
||||
size = total_size - (sector * sector_size);
|
||||
if (size > sector_size)
|
||||
size = sector_size;
|
||||
flag = SECT_FLAG_BACKUP;
|
||||
wolfBoot_copy_sector(&boot, &update, sector);
|
||||
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
|
||||
wolfBoot_set_update_sector_flag(sector, flag);
|
||||
/* FALL THROUGH */
|
||||
case SECT_FLAG_BACKUP:
|
||||
size = total_size - (sector * sector_size);
|
||||
if (size > sector_size)
|
||||
size = sector_size;
|
||||
flag = SECT_FLAG_UPDATED;
|
||||
wolfBoot_copy_sector(&swap, &boot, sector);
|
||||
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
|
||||
wolfBoot_set_update_sector_flag(sector, flag);
|
||||
break;
|
||||
case SECT_FLAG_UPDATED:
|
||||
/* FALL THROUGH */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sector++;
|
||||
/* headers that can be in different positions depending on when the
|
||||
|
@ -526,9 +635,6 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
|
||||
/* get total size */
|
||||
total_size = wolfBoot_get_total_size(&boot, &update);
|
||||
|
||||
if (total_size <= IMAGE_HEADER_SIZE)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* erase to the last sector, writeonce has 2 sectors */
|
||||
|
@ -542,13 +648,9 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
wb_flash_erase(&update, sector * sector_size, sector_size);
|
||||
sector++;
|
||||
}
|
||||
/* mark that our sector flags aren't reliable in testing mode */
|
||||
st = IMG_STATE_FINAL_FLAGS;
|
||||
wolfBoot_set_partition_state(PART_UPDATE, st);
|
||||
/* mark boot partition as testing */
|
||||
st = IMG_STATE_TESTING;
|
||||
wolfBoot_set_partition_state(PART_BOOT, st);
|
||||
wb_flash_erase(&swap, 0, WOLFBOOT_SECTOR_SIZE);
|
||||
/* start re-entrant final erase, return code is only for resumption in
|
||||
* wolfBoot_start*/
|
||||
wolfBoot_swap_and_final_erase(0);
|
||||
/* encryption key was not erased, will be erased by success */
|
||||
#ifdef EXT_FLASH
|
||||
ext_flash_lock();
|
||||
|
@ -695,11 +797,13 @@ int wolfBoot_unlock_disk(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
void RAMFUNCTION wolfBoot_start(void)
|
||||
{
|
||||
int bootRet;
|
||||
int updateRet;
|
||||
#ifndef DISABLE_BACKUP
|
||||
int resumedFinalErase;
|
||||
#endif
|
||||
uint8_t bootState;
|
||||
uint8_t updateState;
|
||||
struct wolfBoot_image boot;
|
||||
|
@ -715,21 +819,25 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
bootRet = wolfBoot_get_partition_state(PART_BOOT, &bootState);
|
||||
updateRet = wolfBoot_get_partition_state(PART_UPDATE, &updateState);
|
||||
|
||||
/* Check if the BOOT partition is still in TESTING,
|
||||
* to trigger fallback.
|
||||
*/
|
||||
if (bootRet == 0 && bootState == IMG_STATE_TESTING) {
|
||||
/* wolfBoot_update_trigger now erases all the sector flags, only trigger
|
||||
* if we're not already updating */
|
||||
if (updateRet || updateState != IMG_STATE_UPDATING) {
|
||||
wolfBoot_update_trigger();
|
||||
#ifndef DISABLE_BACKUP
|
||||
/* resume the final erase in case the power failed before it finished */
|
||||
resumedFinalErase = wolfBoot_swap_and_final_erase(1);
|
||||
|
||||
if (resumedFinalErase != 0)
|
||||
#endif
|
||||
{
|
||||
/* Check if the BOOT partition is still in TESTING,
|
||||
* to trigger fallback.
|
||||
*/
|
||||
if ((bootRet == 0) && (bootState == IMG_STATE_TESTING)) {
|
||||
wolfBoot_update(1);
|
||||
/* Check for new updates in the UPDATE partition or if we were
|
||||
* interrupted during the flags setting */
|
||||
}
|
||||
else if ((updateRet == 0) && (updateState == IMG_STATE_UPDATING)) {
|
||||
/* Check for new updates in the UPDATE partition */
|
||||
wolfBoot_update(0);
|
||||
}
|
||||
wolfBoot_update(1);
|
||||
/* Check for new updates in the UPDATE partition or if we were
|
||||
* interrupted during the flags setting */
|
||||
} else if (updateRet == 0 && (updateState == IMG_STATE_UPDATING || updateState == IMG_STATE_FINAL_FLAGS)) {
|
||||
/* Check for new updates in the UPDATE partition */
|
||||
wolfBoot_update(0);
|
||||
}
|
||||
if ((wolfBoot_open_image(&boot, PART_BOOT) < 0)
|
||||
|| (wolfBoot_verify_integrity(&boot) < 0)
|
||||
|
|
|
@ -52,6 +52,11 @@ int do_cmd(const char *cmd)
|
|||
if (strcmp(cmd, "powerfail") == 0) {
|
||||
return 1;
|
||||
}
|
||||
/* forces a bad write of the boot partition to trigger and test the
|
||||
* emergency fallback feature */
|
||||
if (strcmp(cmd, "emergency") == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(cmd, "get_version") == 0) {
|
||||
printf("%d\n", wolfBoot_current_firmware_version());
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
V=`./wolfboot.elf update_trigger get_version 2>/dev/null`
|
||||
if [ "x$V" != "x1" ]; then
|
||||
echo "Failed first boot with update_trigger"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
V=`./wolfboot.elf success get_version emergency 2>/dev/null`
|
||||
if [ "x$V" != "x1" ]; then
|
||||
echo "Failed fallback (V: $V)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Test successful.
|
||||
exit 0
|
|
@ -47,5 +47,27 @@ if [ "x$V" != "x1" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# make sure it can double revert
|
||||
./wolfboot.elf powerfail 0 get_version 2>/dev/null
|
||||
./wolfboot.elf powerfail 15000 get_version 2>/dev/null
|
||||
./wolfboot.elf powerfail 18000 get_version 2>/dev/null
|
||||
./wolfboot.elf powerfail 1a000 get_version 2>/dev/null
|
||||
# fail on the last sector to stop the encrypt key save and state update
|
||||
./wolfboot.elf powerfail 3e000 get_version 2>/dev/null
|
||||
# may not trigger on non NVM_FLASH_WRITEONCE
|
||||
V=`./wolfboot.elf powerfail 3f000 get_version` 2>/dev/null
|
||||
if [ "x$V" != "x2" ]; then
|
||||
V=`./wolfboot.elf get_version 2>/dev/null`
|
||||
# if we failed on the final boot state write we need to double fallback
|
||||
if [ "x$V" == "x1" ]; then
|
||||
V=`./wolfboot.elf get_version 2>/dev/null`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "x$V" != "x2" ]; then
|
||||
echo "Failed update (V: $V)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo Test successful.
|
||||
exit 0
|
||||
|
|
|
@ -977,29 +977,29 @@ test-all: clean
|
|||
|
||||
|
||||
test-size-all:
|
||||
make test-size SIGN=NONE LIMIT=4776
|
||||
make test-size SIGN=NONE LIMIT=4913
|
||||
make keysclean
|
||||
make test-size SIGN=ED25519 LIMIT=11424
|
||||
make test-size SIGN=ED25519 LIMIT=11529
|
||||
make keysclean
|
||||
make test-size SIGN=ECC256 LIMIT=17824
|
||||
make test-size SIGN=ECC256 LIMIT=17857
|
||||
make keysclean
|
||||
make test-size SIGN=ECC256 NO_ASM=1 LIMIT=13588
|
||||
make test-size SIGN=ECC256 NO_ASM=1 LIMIT=13593
|
||||
make keysclean
|
||||
make test-size SIGN=RSA2048 LIMIT=11104
|
||||
make test-size SIGN=RSA2048 LIMIT=11217
|
||||
make keysclean
|
||||
make test-size SIGN=RSA2048 NO_ASM=1 LIMIT=11804
|
||||
make test-size SIGN=RSA2048 NO_ASM=1 LIMIT=11797
|
||||
make keysclean
|
||||
make test-size SIGN=RSA4096 LIMIT=11884
|
||||
make test-size SIGN=RSA4096 LIMIT=11497
|
||||
make keysclean
|
||||
make test-size SIGN=RSA4096 NO_ASM=1 LIMIT=11980
|
||||
make test-size SIGN=RSA4096 NO_ASM=1 LIMIT=12093
|
||||
make keysclean
|
||||
make test-size SIGN=ECC384 LIMIT=17388
|
||||
make test-size SIGN=ECC384 LIMIT=17309
|
||||
make keysclean
|
||||
make test-size SIGN=ECC384 NO_ASM=1 LIMIT=15024
|
||||
make test-size SIGN=ECC384 NO_ASM=1 LIMIT=15013
|
||||
make keysclean
|
||||
make test-size SIGN=ED448 LIMIT=13536
|
||||
make test-size SIGN=ED448 LIMIT=13645
|
||||
make keysclean
|
||||
make test-size SIGN=RSA3072 LIMIT=11240
|
||||
make test-size SIGN=RSA3072 LIMIT=11353
|
||||
make keysclean
|
||||
make test-size SIGN=RSA3072 NO_ASM=1 LIMIT=11792
|
||||
make test-size SIGN=RSA3072 NO_ASM=1 LIMIT=11905
|
||||
make keysclean
|
||||
|
|
Loading…
Reference in New Issue