Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ tools/unit-tests/unit-policy-create
tools/unit-tests/unit-sign-encrypted-output
tools/unit-tests/unit-update-flash-delta
tools/unit-tests/unit-update-flash-self-update
tools/unit-tests/unit-update-flash-self-update-monolithic
tools/unit-tests/unit-update-flash-hook
tools/unit-tests/unit-loader-tpm-init
tools/unit-tests/unit-update-ram-nofixed
Expand Down
9 changes: 9 additions & 0 deletions docs/firmware_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,15 @@ bytes and the nested application image. Later calls to
`fw_size` bytes starting at `ARCH_FLASH_OFFSET`, spanning into the BOOT
partition.

The persisted header also sets the version a new payload must exceed. A
staged payload is installed only if its version is greater than both the
running bootloader's `WOLFBOOT_VERSION` and the version in the
self-header. The bootloader inside each payload can therefore keep the
same `WOLFBOOT_VERSION` across releases. Without the self-header only
`WOLFBOOT_VERSION` is checked, so the bootloader in each payload must be
built with `WOLFBOOT_VERSION` equal to the payload's signed version,
otherwise the update is rejected.

##### Restrictions

- **Not power-fail safe.** Like all self-updates, a monolithic update
Expand Down
52 changes: 12 additions & 40 deletions hal/aurix_tc3xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@
/* wolfHSM client context and configuration */
#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)

static int _connectCb(void* context, whCommConnected connect);
/* wolfHSM TC3xx port client, which selects the comm buffer and the bridge
* flags. wolfBoot and then the application on CPU0 both use client 0. */
#define HSM_CLIENT 0

/* Client configuration/contexts */
static whTransportMemClientContext tmcCtx[1] = {0};
Expand Down Expand Up @@ -172,8 +174,8 @@ void wolfBoot_panic(void) TC3_LONGCALL;
* to force the HSM core to execute from RAM while the host-driven flash
* command completes.
* The server app must be running first to process a park request */
#define HSM_PARK() (void)tchsmHhHost_HsmPark()
#define HSM_RELEASE() (void)tchsmHhHost_HsmRelease()
#define HSM_PARK() (void)tchsmHhHost_HsmPark(HSM_CLIENT)
#define HSM_RELEASE() (void)tchsmHhHost_HsmRelease(HSM_CLIENT)
#else
#define HSM_PARK()
#define HSM_RELEASE()
Expand Down Expand Up @@ -587,63 +589,33 @@ RAMFUNCTION void ext_flash_unlock(void)

#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT

static int _connectCb(void* context, whCommConnected connect)
{
int ret;

switch (connect) {
case WH_COMM_CONNECTED:
ret = tchsmHhHost2Hsm_Notify(TCHSM_HOST2HSM_NOTIFY_CONNECT);
break;
case WH_COMM_DISCONNECTED:
ret = tchsmHhHost2Hsm_Notify(TCHSM_HOST2HSM_NOTIFY_DISCONNECT);
break;
default:
ret = WH_ERROR_BADARGS;
break;
}

return ret;
}

int hal_hsm_init_connect(void)
{
int rc = 0;
size_t i;

/* init shared memory buffers */
uint32_t* req = (uint32_t*)hsmShmCore0CommBuf;
uint32_t* resp =
(uint32_t*)hsmShmCore0CommBuf + HSM_SHM_CORE0_COMM_BUF_WORDS / 2;
whTransportMemConfig tmcCfg[1] = {{
.req = req,
.req_size = HSM_SHM_CORE0_COMM_BUF_SIZE / 2,
.resp = resp,
.resp_size = HSM_SHM_CORE0_COMM_BUF_SIZE / 2,
}};
int rc = 0;

whTransportMemConfig tmcCfg[1] = {{0}};

/* Client configuration/contexts */
whCommClientConfig cc_conf[1] = {{
.transport_cb = tmcCb,
.transport_context = (void*)tmcCtx,
.transport_config = (void*)tmcCfg,
.client_id = WOLFBOOT_WOLFHSM_CLIENT_ID,
.connect_cb = _connectCb,
.connect_cb = hsm_ipc_get_connect_cb(HSM_CLIENT),
}};

whClientConfig c_conf[1] = {{
.comm = cc_conf,
}};

rc = hsm_ipc_init();
rc = hsm_ipc_init(HSM_CLIENT);
if (rc != WH_ERROR_OK) {
return rc;
}

/* init shared memory buffers */
for (i = 0; i < HSM_SHM_CORE0_COMM_BUF_WORDS; i++) {
hsmShmCore0CommBuf[i] = 0;
rc = hsm_ipc_transport_config(HSM_CLIENT, tmcCfg);
if (rc != WH_ERROR_OK) {
return rc;
}

rc = wh_Client_Init(&hsmClientCtx, c_conf);
Expand Down
12 changes: 11 additions & 1 deletion src/update_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,17 @@ void RAMFUNCTION wolfBoot_check_self_update(void)
(wolfBoot_open_image(&update, PART_UPDATE) == 0) &&
wolfBoot_get_image_type(PART_UPDATE) == (HDR_IMG_TYPE_WOLFBOOT | HDR_IMG_TYPE_AUTH)) {
uint32_t update_version = wolfBoot_update_firmware_version();
if (update_version <= wolfboot_version) {
uint32_t current_version = wolfboot_version;
#if defined(WOLFBOOT_SELF_UPDATE_MONOLITHIC) && defined(WOLFBOOT_SELF_HEADER)
/* The self-header has the installed payload's version, which may be
* newer than the WOLFBOOT_VERSION this bootloader was built with */
uint32_t self_version = wolfBoot_get_self_version();

if (self_version > current_version) {
current_version = self_version;
}
#endif
if (update_version <= current_version) {
wolfBoot_erase_partition(PART_UPDATE);
return;
}
Expand Down
3 changes: 2 additions & 1 deletion test-app/app_aurix_tc3xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static void hsmUpdate(void)
if (wolfBoot_current_firmware_version() > BASE_FW_VERSION) {
return;
}
rc = tchsmHhHost_HsmUpdateTrigger();
/* Client 0 is the wolfHSM client of this core */
rc = tchsmHhHost_HsmUpdateTrigger(0);
if (rc == 0) {
wolfBoot_printf("HSM update triggered\n");
}
Expand Down
6 changes: 6 additions & 0 deletions tools/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ test-sim-self-update-monolithic: wolfboot.bin test-app/image_v1_signed.bin FORCE
# Same as test-sim-self-update-monolithic, but also verifies that the
# self-header was persisted at WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS and
# matches the signing tool's --header-only output byte-for-byte.
# A second boot checks that the payload is not installed again.
#
test-sim-self-update-monolithic-self-header: wolfboot.bin test-app/image_v1_signed.bin FORCE
@echo "=== Simulator Monolithic Self-Update + Self-Header Test ==="
Expand Down Expand Up @@ -341,6 +342,11 @@ test-sim-self-update-monolithic-self-header: wolfboot.bin test-app/image_v1_sign
$(Q)dd if=internal_flash.dd bs=1 skip=$$(($(WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=$$(($(WOLFBOOT_SECTOR_SIZE))) of=persisted_hdr.dd 2>/dev/null
$(Q)cmp -n $$(($(IMAGE_HEADER_SIZE))) persisted_hdr.dd monolithic_payload_v2_header.bin
@echo " Self-header persisted correctly: PASSED"
@# Boot again. The self-header shows the payload is already installed, so
@# wolfBoot should erase it from the update partition, not install it again.
$(Q)./wolfboot.elf get_version || true
$(Q)dd if=internal_flash.dd bs=1 skip=$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=4 2>/dev/null | od -An -tx1 | grep -q "ff ff ff ff"
@echo " Installed payload erased from UPDATE on next boot: PASSED"
@echo "=== Monolithic Self-Update + Self-Header Test PASSED ==="

# Test that an oversized monolithic self-update is rejected. The payload is
Expand Down
17 changes: 17 additions & 0 deletions tools/unit-tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ TESTS:=unit-parser unit-parser-large-header unit-fdt unit-extflash unit-string \
unit-update-flash-hook \
unit-update-flash-self-update \
unit-update-flash-self-update-ecc \
unit-update-flash-self-update-monolithic \
unit-nsc-update \
unit-update-flash-enc unit-update-flash-enc-full unit-update-flash-enc-intswap unit-update-ram unit-update-ram-fit unit-update-ram-uboot unit-update-ram-enc unit-update-ram-enc-nopart unit-update-ram-nofixed unit-update-ram-nofixed-noramboot unit-update-ram-noramboot unit-update-ram-custom-trailer unit-custom-trailer-nopart unit-update-flash-hwswap unit-pkcs11_store unit-psa_store unit-wolfhsm_flash_hal unit-disk \
unit-update-disk unit-update-disk-confirm unit-update-disk-golden unit-update-disk-fsp unit-update-disk-oob unit-update-disk-fit unit-update-disk-fit-ramdisk unit-multiboot unit-boot-x86-fsp unit-loader-tpm-init unit-qspi-flash unit-fwtpm-stub unit-tpm-rsa-exp \
Expand Down Expand Up @@ -408,6 +409,17 @@ unit-update-flash-self-update-ecc:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -
-DNVM_FLASH_JOURNAL -DNVM_FLASH_ECC -DWOLFBOOT_FLASH_WRITE_UNIT=32 \
-DWOLFBOOT_SECTOR_SIZE=0x1000 -DWOLFBOOT_SELF_HEADER \
-DWOLFBOOT_PARTITION_SELF_HEADER_ADDRESS=0xCD004000
# Same as unit-update-flash-self-update, plus monolithic mode and a self-header
# (in the unused SWAP sector), to check that an update is only installed if it
# is newer than the version in the self-header. Some addresses are plain
# numbers because image.c is built separately and cannot see MOCK_ADDRESS_*.
unit-update-flash-self-update-monolithic:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \
-DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT -DPART_SWAP_EXT \
-DRAM_CODE -DARCH_SIM -DUNIT_TEST_SELF_UPDATE_ONLY -DWOLFBOOT_SELF_UPDATE_MONOLITHIC \
-DWOLFBOOT_SELF_HEADER -DWOLFBOOT_SELF_HEADER_EXT \
-DWOLFBOOT_PARTITION_SELF_HEADER_ADDRESS=0xCE000000 \
-DARCH_FLASH_OFFSET=0xCD000000 -DWOLFBOOT_VERSION=7 \
-DWOLFBOOT_ORIGIN=MOCK_ADDRESS_BOOT -DBOOTLOADER_PARTITION_SIZE=WOLFBOOT_PARTITION_SIZE
unit-update-ram-fit:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \
-DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT \
-DPART_SWAP_EXT -DPART_BOOT_EXT -DWOLFBOOT_DUALBOOT -DNO_XIP \
Expand Down Expand Up @@ -872,6 +884,11 @@ unit-update-flash-self-update-ecc: ../../include/target.h unit-update-flash.c
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c \
$(CFLAGS) $(LDFLAGS)

unit-update-flash-self-update-monolithic: ../../include/target.h unit-update-flash.c
gcc -o $@ unit-update-flash.c ../../src/image.c \
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c \
$(CFLAGS) $(LDFLAGS)

unit-sdhci-response-bits: ../../include/target.h unit-sdhci-response-bits.c
gcc -o $@ $^ $(CFLAGS) -ffunction-sections -fdata-sections $(LDFLAGS) \
-Wl,--gc-sections
Expand Down
100 changes: 100 additions & 0 deletions tools/unit-tests/unit-update-flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,91 @@ START_TEST (test_self_update_ecc_whole_units)
}
END_TEST
#endif

#if defined(WOLFBOOT_SELF_UPDATE_MONOLITHIC) && defined(WOLFBOOT_SELF_HEADER)
/* Write a self-header with only the magic, size and version fields */
static void set_self_header_version(uint32_t version)
{
uintptr_t hdr = WOLFBOOT_PARTITION_SELF_HEADER_ADDRESS;
uint32_t magic = WOLFBOOT_MAGIC;
uint32_t size_img = host_to_img_u32(TEST_SIZE_SMALL);
uint32_t word = 4 << 16 | HDR_VERSION;
uint32_t version_img = host_to_img_u32(version);

ext_flash_unlock();
ext_flash_erase(hdr, WOLFBOOT_SELF_HEADER_SIZE);
ext_flash_write(hdr, (void *)&magic, 4);
ext_flash_write(hdr + 4, (void *)&size_img, 4);
ext_flash_write(hdr + 8, (void *)&word, 4);
ext_flash_write(hdr + 12, (void *)&version_img, 4);
ext_flash_lock();
}

static void stage_self_update(uint32_t version)
{
add_payload_type(PART_UPDATE, version, TEST_SIZE_SMALL,
HDR_IMG_TYPE_WOLFBOOT | HDR_IMG_TYPE_AUTH);
ext_flash_unlock();
wolfBoot_set_partition_state(PART_UPDATE, IMG_STATE_UPDATING);
ext_flash_lock();
}

/* The update has the same version as the self-header, so it is already
* installed and should be erased, not installed again */
START_TEST (test_self_update_self_header_sameversion_erased)
{
reset_mock_stats();
prepare_flash();
clear_erase_stats();
set_self_header_version(WOLFBOOT_VERSION + 2);
stage_self_update(WOLFBOOT_VERSION + 2);

wolfBoot_check_self_update();

ck_assert_int_eq(arch_reboot_called, 0);
ck_assert_int_ge(erased_update, 1);
ck_assert_uint_eq(*(uint32_t *)(uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS,
0xFFFFFFFFu);
cleanup_flash();
}
END_TEST

/* The update is older than the self-header version, so it should be erased
* even though it is newer than WOLFBOOT_VERSION */
START_TEST (test_self_update_self_header_oldversion_erased)
{
reset_mock_stats();
prepare_flash();
clear_erase_stats();
set_self_header_version(WOLFBOOT_VERSION + 2);
stage_self_update(WOLFBOOT_VERSION + 1);

wolfBoot_check_self_update();

ck_assert_int_eq(arch_reboot_called, 0);
ck_assert_int_ge(erased_update, 1);
ck_assert_uint_eq(*(uint32_t *)(uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS,
0xFFFFFFFFu);
cleanup_flash();
}
END_TEST

START_TEST (test_self_update_self_header_newversion_installs)
{
reset_mock_stats();
prepare_flash();
clear_erase_stats();
set_self_header_version(WOLFBOOT_VERSION + 2);
stage_self_update(WOLFBOOT_VERSION + 3);

wolfBoot_check_self_update();

ck_assert_int_eq(arch_reboot_called, 1);
ck_assert_uint_eq(wolfBoot_get_self_version(), WOLFBOOT_VERSION + 3);
cleanup_flash();
}
END_TEST
#endif /* WOLFBOOT_SELF_UPDATE_MONOLITHIC && WOLFBOOT_SELF_HEADER */
#endif

#ifndef UNIT_TEST_SELF_UPDATE_ONLY
Expand Down Expand Up @@ -2284,11 +2369,21 @@ Suite *wolfboot_suite(void)
#ifdef NVM_FLASH_ECC
TCase *self_update_ecc = tcase_create("Self update on ECC flash");
#endif
#if defined(WOLFBOOT_SELF_UPDATE_MONOLITHIC) && defined(WOLFBOOT_SELF_HEADER)
TCase *self_header_sameversion = tcase_create("Self update self-header same version erased");
TCase *self_header_oldversion = tcase_create("Self update self-header older version erased");
TCase *self_header_newversion = tcase_create("Self update self-header newer version installs");
#endif

tcase_add_test(self_update_sameversion, test_self_update_sameversion_erased);
tcase_add_test(self_update_oldversion, test_self_update_oldversion_erased);
tcase_add_test(self_update_invalid_integrity, test_self_update_newversion_invalid_integrity_denied);
tcase_add_test(self_update_success, test_self_update_newversion_copies_and_reboots);
#if defined(WOLFBOOT_SELF_UPDATE_MONOLITHIC) && defined(WOLFBOOT_SELF_HEADER)
tcase_add_test(self_header_sameversion, test_self_update_self_header_sameversion_erased);
tcase_add_test(self_header_oldversion, test_self_update_self_header_oldversion_erased);
tcase_add_test(self_header_newversion, test_self_update_self_header_newversion_installs);
#endif

suite_add_tcase(s, self_update_sameversion);
suite_add_tcase(s, self_update_oldversion);
Expand All @@ -2298,6 +2393,11 @@ Suite *wolfboot_suite(void)
tcase_add_test(self_update_ecc, test_self_update_ecc_whole_units);
suite_add_tcase(s, self_update_ecc);
#endif
#if defined(WOLFBOOT_SELF_UPDATE_MONOLITHIC) && defined(WOLFBOOT_SELF_HEADER)
suite_add_tcase(s, self_header_sameversion);
suite_add_tcase(s, self_header_oldversion);
suite_add_tcase(s, self_header_newversion);
#endif
#endif
return s;
#else
Expand Down
Loading