Merge pull request #463 from jpbland1/bad-image-recovery

add emergency fallback test, currently fails due to
pull/408/head
David Garske 2024-07-10 14:08:48 -07:00 committed by GitHub
commit b9dc7eee46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 361 additions and 150 deletions

View File

@ -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: |

View File

@ -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;
}
}

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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