F-12922: do not block fallback to a valid image in wolfBoot_start

The version gate in the retry loop panicked whenever the selected
candidate failed verification and the fallback partition carried a
lower version, even though that image is valid and signed. A single
corrupted higher-version image bricked the device instead of falling
back. The gate only ever fired on the failure path (candidate
selection already prefers the higher version), so remove it; the
TESTING-state anti-rollback check in wolfBoot_dualboot_candidate()
still guards the confirmed-update path.
pull/892/head
Daniele Lacamera 2026-09-15 08:24:11 +02:00
parent f0ad5692d2
commit 63f1ce7872
3 changed files with 25 additions and 38 deletions

View File

@ -314,12 +314,6 @@ void RAMFUNCTION wolfBoot_start(void)
* kernel directly. */
uintptr_t bl31_entry = 0;
#endif
#if !defined(ALLOW_DOWNGRADE) && defined(WOLFBOOT_FIXED_PARTITIONS)
uint32_t boot_v = wolfBoot_current_firmware_version();
uint32_t update_v = wolfBoot_update_firmware_version();
uint32_t max_v = (boot_v > update_v) ? boot_v : update_v;
#endif /* !ALLOW_DOWNGRADE && WOLFBOOT_FIXED_PARTITIONS */
for (;;) {
/* Each open needs fresh image state: wolfBoot_open_image_address()
* adopts load_address only when hdr is NULL, and the external
@ -349,17 +343,6 @@ void RAMFUNCTION wolfBoot_start(void)
wolfBoot_panic();
break;
}
#if !defined(ALLOW_DOWNGRADE) && defined(WOLFBOOT_FIXED_PARTITIONS)
{
uint32_t active_v = (active == PART_UPDATE) ? update_v : boot_v;
if ((max_v > 0U) && (active_v < max_v)) {
wolfBoot_printf("Rollback to lower version not allowed\n");
wolfBoot_panic();
break;
}
}
#endif /* !ALLOW_DOWNGRADE && WOLFBOOT_FIXED_PARTITIONS */
#if defined(WOLFBOOT_DUALBOOT) && defined(WOLFBOOT_FIXED_PARTITIONS)
wolfBoot_printf("Trying %s partition at %p\n",
active == PART_BOOT ? "Boot" : "Update", source_address);

View File

@ -184,16 +184,15 @@ START_TEST (test_noramboot_sunnyday) {
}
END_TEST
/* Regression test for F-4410: firmware versions with the high bit set
* (>= 0x80000000) must still feed the anti-rollback guard in wolfBoot_start.
/* Regression test for F-4410 + F-12922: firmware versions with the high
* bit set (>= 0x80000000) must be read without signed-int clamping (the
* two version asserts below), and a failed high-version image must not
* block fallback to the lower-versioned (but valid) UPDATE partition.
*
* BOOT carries the higher version but is marked oversize so wolfBoot_open_image()
* rejects it and the boot path falls back to the lower-versioned (but valid)
* UPDATE partition. That downgrade must be denied. Before the fix the versions
* were cast through a signed int and clamped to 0, collapsing max_v to 0 and
* silently bypassing the "(max_v > 0U)" guard, so the lower UPDATE image was
* staged for boot. */
START_TEST (test_noramboot_highversion_rollback_denied) {
* BOOT carries the higher version but is marked oversize so
* wolfBoot_open_image() rejects it; the boot path must fall back to the
* valid UPDATE image instead of panicking on the version difference. */
START_TEST (test_noramboot_fallback_to_lower_version) {
uint32_t oversize = WOLFBOOT_PARTITION_SIZE;
reset_mock_stats();
@ -212,10 +211,10 @@ START_TEST (test_noramboot_highversion_rollback_denied) {
wolfBoot_start();
/* Rollback to the lower UPDATE version must be denied: wolfBoot panics and
* stages nothing. */
ck_assert(!wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 1);
/* A failed high-version boot image must not block fallback to the
* valid lower-version update image (F-12922). */
ck_assert(wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 0);
cleanup_flash();
}
END_TEST
@ -255,7 +254,7 @@ Suite *wolfboot_suite(void)
tcase_add_test(sunnyday, test_noramboot_sunnyday);
tcase_add_test(ext_short_read,
test_noramboot_ext_flash_short_read_rejected);
tcase_add_test(rollback_denied, test_noramboot_highversion_rollback_denied);
tcase_add_test(rollback_denied, test_noramboot_fallback_to_lower_version);
suite_add_tcase(s, sunnyday);
suite_add_tcase(s, ext_short_read);
suite_add_tcase(s, rollback_denied);

View File

@ -434,9 +434,10 @@ START_TEST (test_invalid_update_type) {
ext_flash_lock();
wolfBoot_update_trigger();
wolfBoot_start();
ck_assert(!wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 1);
ck_assert_int_eq(get_version_ramloaded(), 2);
/* Failed update must fall back to the valid boot image, not panic. */
ck_assert(wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 0);
ck_assert_int_eq(get_version_ramloaded(), 1);
cleanup_flash();
}
@ -453,8 +454,10 @@ START_TEST (test_update_toolarge) {
wolfBoot_update_trigger();
wolfBoot_start();
ck_assert(!wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 1);
/* Failed update must fall back to the valid boot image, not panic. */
ck_assert(wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 0);
ck_assert_int_eq(get_version_ramloaded(), 1);
cleanup_flash();
}
@ -471,8 +474,10 @@ START_TEST (test_invalid_sha) {
ext_flash_lock();
wolfBoot_update_trigger();
wolfBoot_start();
ck_assert(!wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 1);
/* Failed update must fall back to the valid boot image, not panic. */
ck_assert(wolfBoot_staged_ok);
ck_assert_int_eq(wolfBoot_panicked, 0);
ck_assert_int_eq(get_version_ramloaded(), 1);
cleanup_flash();
}