From 394f160a83aba53bfceb1c4f3d224a5c2a90ff89 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 7 Sep 2026 14:40:35 +0200 Subject: [PATCH] F-12873: update_disk: FSP low-mem check reuses validated slot_max The final image-size check re-derived the low-memory limit with a uint32 subtraction and no ordering check, so an inverted tolum wrapped into a near-2^32 limit and accepted any image. Compare the tolum/load_address ordering in 32-bit (low-memory) form when computing slot_max, and reuse that validated value in the check. Add a unit test for the inverted-tolum case (fails closed, both slots rejected). --- src/update_disk.c | 21 +++++++++++++-------- tools/unit-tests/unit-update-disk-fsp.c | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/update_disk.c b/src/update_disk.c index 66ada952..0d77858c 100644 --- a/src/update_disk.c +++ b/src/update_disk.c @@ -547,11 +547,15 @@ void RAMFUNCTION wolfBoot_start(void) * The header sits ahead of the payload in the same file, hence the * IMAGE_HEADER_SIZE. */ #if defined(WOLFBOOT_FSP) - /* Fail closed on an inverted tolum: the subtraction would otherwise wrap - * to a near-2^64 bound, which is the opposite of a cap. */ - if ((uintptr_t)(stage2_params->tolum) > (uintptr_t)load_address) { - slot_max = (uint64_t)(uintptr_t)(stage2_params->tolum) - - (uint64_t)(uintptr_t)load_address; + /* Fail closed on an inverted tolum: with tolum at or below the load + * address there is no low-memory window, so the cap is zero. Both + * are low-memory addresses, so compare them in their 32-bit form. + * The subtraction would otherwise wrap into a near-2^32 bound, which + * is the opposite of a cap. */ + if ((uint32_t)(uintptr_t)(stage2_params->tolum) > + (uint32_t)(uintptr_t)load_address) { + slot_max = (uint64_t)(uint32_t)(uintptr_t)(stage2_params->tolum) - + (uint64_t)(uint32_t)(uintptr_t)load_address; } else { slot_max = 0; @@ -697,9 +701,10 @@ void RAMFUNCTION wolfBoot_start(void) #endif #ifdef WOLFBOOT_FSP - /* Verify image size fits in low memory */ - if (os_image.fw_size > ((uint32_t)(stage2_params->tolum) - - (uint32_t)(uintptr_t)load_address)) { + /* Verify image size fits in low memory. Reuse the validated + * slot_max: it is zero when tolum is inverted, where the raw + * subtraction would wrap into a near-2^32 limit. */ + if (os_image.fw_size > slot_max) { wolfBoot_printf("Image size %u doesn't fit in low memory\r\n", os_image.fw_size); selected ^= 1; diff --git a/tools/unit-tests/unit-update-disk-fsp.c b/tools/unit-tests/unit-update-disk-fsp.c index 8a775afb..08694902 100644 --- a/tools/unit-tests/unit-update-disk-fsp.c +++ b/tools/unit-tests/unit-update-disk-fsp.c @@ -236,6 +236,22 @@ START_TEST(test_fsp_both_slots_oversized_panics) } END_TEST +START_TEST(test_fsp_inverted_tolum_rejects_both_slots) +{ + /* tolum below the load address inverts the low-memory limit. The + * limit must fail closed (no slot may load), not wrap into a + * near-2^32 limit that accepts any image. */ + reset_mocks(); + mock_stage2_params.tolum = + (uint32_t)((uintptr_t)load_buffer - 1); + + wolfBoot_start(); + + ck_assert_int_gt(wolfBoot_panicked, 0); + ck_assert_int_eq(mock_do_boot_called, 0); +} +END_TEST + START_TEST(test_fsp_fitting_slot_boots) { /* Both slots fit and versions are equal: primary (A) boots. */ @@ -258,6 +274,7 @@ Suite *wolfboot_suite(void) tcase_add_test(tc, test_fsp_oversized_slot_falls_back_to_other_slot); tcase_add_test(tc, test_fsp_both_slots_oversized_panics); + tcase_add_test(tc, test_fsp_inverted_tolum_rejects_both_slots); tcase_add_test(tc, test_fsp_fitting_slot_boots); suite_add_tcase(s, tc);