diff --git a/src/update_flash.c b/src/update_flash.c index 77bc0ed1..5f398d71 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -1332,12 +1332,16 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) #else /* DISABLE_BACKUP */ #ifdef WOLFBOOT_ELF_FLASH_SCATTER unsigned long entry; - void* base = (void*)WOLFBOOT_PARTITION_BOOT_ADDRESS; wolfBoot_printf("ELF Scattered image digest check\n"); if (wolfBoot_check_flash_image_elf(PART_BOOT, &entry) < 0) { wolfBoot_printf("ELF Scattered image digest check: failed. Restoring " "scattered image...\n"); - wolfBoot_load_flash_image_elf(PART_BOOT, &entry, PART_IS_EXT(boot)); + if (wolfBoot_load_flash_image_elf(PART_BOOT, &entry, + PART_IS_EXT(&boot)) < 0) { + wolfBoot_printf( + "ELF: [UPDATE] ERROR: could not store scattered image\n"); + wolfBoot_panic(); + } if (wolfBoot_check_flash_image_elf(PART_BOOT, &entry) < 0) { wolfBoot_printf( "Fatal: Could not verify digest after scattering. Panic().\n"); diff --git a/tools/unit-tests/Makefile b/tools/unit-tests/Makefile index 234ccf77..cd1e1b10 100644 --- a/tools/unit-tests/Makefile +++ b/tools/unit-tests/Makefile @@ -222,6 +222,7 @@ run: $(TESTS) python3 unit-sign-delta-cert-inv-off.py || exit 1 python3 unit-sign-delta-basehash-cleanup.py || exit 1 python3 unit-delta-sector-align.py || exit 1 + python3 unit-elf-scatter-db-build.py || exit 1 python3 unit-sign-custom-tlv-le.py || exit 1 python3 unit-sign-custom-tlv-large.py || exit 1 python3 unit-sign-custom-tlv-pubkey-der.py || exit 1 @@ -273,6 +274,15 @@ unit-update-flash-delta-misalign:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -D -DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT -DPART_SWAP_EXT \ -DDELTA_UPDATES -DDELTA_BLOCK_SIZE=1536 -D__WOLFBOOT \ -DWOLFBOOT_ORIGIN=MOCK_ADDRESS_BOOT -DBOOTLOADER_PARTITION_SIZE=WOLFBOOT_PARTITION_SIZE +# Compile-only check for the DISABLE_BACKUP + WOLFBOOT_ELF_FLASH_SCATTER + +# EXT_FLASH combination: the ELF restore block in wolfBoot_update() must +# compile (it used to pass a struct where PART_IS_EXT expects a pointer). +# Used by unit-elf-scatter-db-build.py only, so it is not part of $(TESTS). +unit-update-flash-elf-scatter-db:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \ + -DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT -DPART_SWAP_EXT \ + -DWOLFBOOT_ELF_FLASH_SCATTER -DWOLFBOOT_ELF -DIMAGE_HEADER_SIZE=256 \ + -DDISABLE_BACKUP -D__WOLFBOOT \ + -DWOLFBOOT_ORIGIN=MOCK_ADDRESS_BOOT -DBOOTLOADER_PARTITION_SIZE=WOLFBOOT_PARTITION_SIZE unit-update-flash-self-update: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 \ @@ -821,6 +831,9 @@ unit-update-flash-delta-misalign: ../../include/target.h unit-update-flash.c gcc -o $@ unit-update-flash.c ../../src/image.c ../../src/delta.c \ $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS) +unit-update-flash-elf-scatter-db: ../../include/target.h unit-update-flash.c FORCE + gcc -c -o /dev/null unit-update-flash.c $(CFLAGS) + unit-update-flash-enc:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \ -DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT \ -DPART_SWAP_EXT -DEXT_ENCRYPTED -DENCRYPT_WITH_CHACHA -DHAVE_CHACHA \ diff --git a/tools/unit-tests/unit-elf-scatter-db-build.py b/tools/unit-tests/unit-elf-scatter-db-build.py new file mode 100644 index 00000000..576b79b1 --- /dev/null +++ b/tools/unit-tests/unit-elf-scatter-db-build.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# unit-elf-scatter-db-build.py +# +# Compile check for the DISABLE_BACKUP + WOLFBOOT_ELF_FLASH_SCATTER + +# EXT_FLASH combination: the ELF-scatter restore block in +# wolfBoot_update() (src/update_flash.c) used to pass the boot struct by +# value to the pointer-taking PART_IS_EXT macro, so this configuration +# failed to build and the branch could never be exercised. It must now +# compile, with the load result checked like in wolfBoot_start(). +# +# Copyright (C) 2026 wolfSSL Inc. +# +# This file is part of wolfBoot. +# +# wolfBoot is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# wolfBoot 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + +import subprocess +import sys + + +def main(): + p = subprocess.run(["make", "unit-update-flash-elf-scatter-db"], + capture_output=True, text=True) + if p.returncode != 0: + print("FAIL: DISABLE_BACKUP + ELF scatter + EXT_FLASH " + "does not compile:\n") + print(p.stderr[-2000:]) + return 1 + print("PASS: DISABLE_BACKUP + ELF scatter + EXT_FLASH compiles") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/unit-tests/unit-update-flash.c b/tools/unit-tests/unit-update-flash.c index dad19d97..26837d42 100644 --- a/tools/unit-tests/unit-update-flash.c +++ b/tools/unit-tests/unit-update-flash.c @@ -1280,6 +1280,7 @@ START_TEST (test_empty_boot_but_update_sha_corrupted_denied) { cleanup_flash(); } +#ifndef DISABLE_BACKUP START_TEST (test_swap_resume_noop) { reset_mock_stats(); @@ -1291,6 +1292,7 @@ START_TEST (test_swap_resume_noop) cleanup_flash(); } END_TEST +#endif START_TEST (test_diffbase_version_reads) { @@ -1868,7 +1870,9 @@ Suite *wolfboot_suite(void) tcase_add_test(emergency_rollback_failure_due_to_bad_update, test_emergency_rollback_failure_due_to_bad_update); tcase_add_test(empty_boot_partition_update, test_empty_boot_partition_update); tcase_add_test(empty_boot_but_update_sha_corrupted_denied, test_empty_boot_but_update_sha_corrupted_denied); +#ifndef DISABLE_BACKUP tcase_add_test(swap_resume, test_swap_resume_noop); +#endif tcase_add_test(diffbase_version, test_diffbase_version_reads); tcase_add_test(diffbase_version, test_diffbase_version_reads_from_little_endian_bytes); tcase_add_test(get_total_size, test_get_total_size_preserves_uint32_range);