mirror of https://github.com/wolfSSL/wolfBoot.git
F-9740: update_disk: FSP low-mem rejection falls back to other slot
The WOLFBOOT_FSP low-memory size check was the only per-slot rejection in the boot retry loop that used a bare break, so an image whose header-declared fw_size exceeded the tolum window aborted the boot instead of trying the other slot. Every other rejection in the same loop switches partitions and retries; match that.pull/882/head
parent
77fe733e7f
commit
a2d5543ebb
|
|
@ -702,7 +702,8 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
(uint32_t)(uintptr_t)load_address)) {
|
||||
wolfBoot_printf("Image size %u doesn't fit in low memory\r\n",
|
||||
os_image.fw_size);
|
||||
break;
|
||||
selected ^= 1;
|
||||
continue;
|
||||
}
|
||||
/* Log memory load */
|
||||
x86_log_memory_load((uint32_t)(uintptr_t)load_address,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,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-enc unit-update-flash-enc-full unit-update-ram unit-update-ram-uboot unit-update-ram-enc unit-update-ram-enc-nopart unit-update-ram-nofixed unit-update-ram-noramboot unit-update-flash-hwswap unit-pkcs11_store unit-psa_store unit-wolfhsm_flash_hal unit-disk \
|
||||
unit-update-disk unit-update-disk-oob unit-update-disk-fit unit-multiboot unit-boot-x86-fsp unit-loader-tpm-init unit-qspi-flash unit-fwtpm-stub unit-tpm-rsa-exp \
|
||||
unit-update-disk unit-update-disk-fsp unit-update-disk-oob unit-update-disk-fit unit-multiboot unit-boot-x86-fsp unit-loader-tpm-init unit-qspi-flash unit-fwtpm-stub unit-tpm-rsa-exp \
|
||||
unit-image-nopart unit-image-sha384 unit-image-sha3-384 unit-image-dts \
|
||||
unit-image-dts-sha384 unit-image-dts-sha3-384 unit-store-sbrk \
|
||||
unit-tpm-blob unit-policy-create unit-policy-sign unit-rot-auth unit-sdhci-response-bits \
|
||||
|
|
@ -899,6 +899,16 @@ unit-update-flash-hwswap: ../../include/target.h unit-update-flash-hwswap.c
|
|||
unit-update-disk: ../../include/target.h unit-update-disk.c
|
||||
gcc -o $@ unit-update-disk.c $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
# WOLFBOOT_FSP (x86) boot path of update_disk.c: the low-memory (tolum)
|
||||
# size check must reject a slot and fall back to the other one, like every
|
||||
# other per-slot rejection in the retry loop.
|
||||
unit-update-disk-fsp:CFLAGS+=-DMOCK_PARTITIONS -DPRINTF_ENABLED -DWOLFBOOT_FSP \
|
||||
-DUCODE0_ADDRESS=0 -DWOLFBOOT_LOAD_BASE=0x100000 \
|
||||
-DWOLFBOOT_ORIGIN=MOCK_ADDRESS_BOOT \
|
||||
-DBOOTLOADER_PARTITION_SIZE=WOLFBOOT_PARTITION_SIZE
|
||||
unit-update-disk-fsp: ../../include/target.h unit-update-disk-fsp.c
|
||||
gcc -o $@ unit-update-disk-fsp.c $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
unit-update-disk-oob: ../../include/target.h unit-update-disk-oob.c
|
||||
gcc -o $@ unit-update-disk-oob.c $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,277 @@
|
|||
/* unit-update-disk-fsp.c
|
||||
*
|
||||
* Unit tests for the WOLFBOOT_FSP (x86 FSP) boot path of update_disk.c:
|
||||
* the low-memory (tolum) size check must reject a slot and try the other
|
||||
* one, like every other per-slot rejection in the retry loop.
|
||||
*/
|
||||
|
||||
#define WOLFBOOT_UPDATE_DISK
|
||||
#define WOLFBOOT_SELF_UPDATE_MONOLITHIC
|
||||
#define RAM_CODE
|
||||
#define WOLFBOOT_SELF_HEADER
|
||||
#define IMAGE_HEADER_SIZE 256
|
||||
#define BOOT_PART_A 0
|
||||
#define BOOT_PART_B 1
|
||||
#define MOCK_ADDRESS_BOOT 0xCD000000
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <check.h>
|
||||
|
||||
#include "hal.h"
|
||||
#include "target.h"
|
||||
#include "wolfboot/wolfboot.h"
|
||||
#include "image.h"
|
||||
#include "loader.h"
|
||||
#include "stage2_params.h"
|
||||
#include "x86/common.h"
|
||||
|
||||
#define TEST_PAYLOAD_SIZE 64
|
||||
|
||||
static uint8_t load_buffer[TEST_PAYLOAD_SIZE];
|
||||
#define WOLFBOOT_LOAD_ADDRESS ((uintptr_t)load_buffer)
|
||||
|
||||
static uint8_t part_a_image[IMAGE_HEADER_SIZE + TEST_PAYLOAD_SIZE];
|
||||
static uint8_t part_b_image[IMAGE_HEADER_SIZE + TEST_PAYLOAD_SIZE];
|
||||
static int mock_do_boot_called;
|
||||
static const uint32_t *mock_boot_address;
|
||||
static struct stage2_parameter mock_stage2_params;
|
||||
|
||||
static void set_u16_le(uint8_t *dst, uint16_t value)
|
||||
{
|
||||
dst[0] = (uint8_t)(value & 0xFF);
|
||||
dst[1] = (uint8_t)(value >> 8);
|
||||
}
|
||||
|
||||
static void set_u32_le(uint8_t *dst, uint32_t value)
|
||||
{
|
||||
dst[0] = (uint8_t)(value & 0xFF);
|
||||
dst[1] = (uint8_t)((value >> 8) & 0xFF);
|
||||
dst[2] = (uint8_t)((value >> 16) & 0xFF);
|
||||
dst[3] = (uint8_t)((value >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/* fw_size may legitimately claim more than the bytes actually present in
|
||||
* the partition buffer: the low-memory check must reject such a slot
|
||||
* before the payload is read. */
|
||||
static void build_image(uint8_t *image, uint32_t version, uint32_t fw_size,
|
||||
uint8_t fill)
|
||||
{
|
||||
memset(image, 0, IMAGE_HEADER_SIZE + TEST_PAYLOAD_SIZE);
|
||||
set_u32_le(image, WOLFBOOT_MAGIC);
|
||||
set_u32_le(image + sizeof(uint32_t), fw_size);
|
||||
set_u16_le(image + IMAGE_HEADER_OFFSET, HDR_VERSION);
|
||||
set_u16_le(image + IMAGE_HEADER_OFFSET + sizeof(uint16_t), 4);
|
||||
set_u32_le(image + IMAGE_HEADER_OFFSET + 2 * sizeof(uint16_t), version);
|
||||
memset(image + IMAGE_HEADER_SIZE, fill, TEST_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
static void reset_mocks(void)
|
||||
{
|
||||
memset(load_buffer, 0, sizeof(load_buffer));
|
||||
build_image(part_a_image, 7, TEST_PAYLOAD_SIZE, 0xA1);
|
||||
build_image(part_b_image, 7, TEST_PAYLOAD_SIZE, 0xB2);
|
||||
mock_do_boot_called = 0;
|
||||
mock_boot_address = NULL;
|
||||
/* The image must fit between load_address and tolum: exactly one
|
||||
* TEST_PAYLOAD_SIZE payload. */
|
||||
mock_stage2_params.tolum =
|
||||
(uint32_t)((uintptr_t)load_buffer + TEST_PAYLOAD_SIZE);
|
||||
wolfBoot_panicked = 0;
|
||||
}
|
||||
|
||||
/* --- mocks ---------------------------------------------------------- */
|
||||
|
||||
int disk_init(int drv)
|
||||
{
|
||||
(void)drv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int disk_open(int drv)
|
||||
{
|
||||
(void)drv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void disk_close(int drv)
|
||||
{
|
||||
(void)drv;
|
||||
}
|
||||
|
||||
int disk_part_read(int drv, int part, uint64_t off, uint64_t sz, uint8_t *buf)
|
||||
{
|
||||
uint8_t *image;
|
||||
uint64_t max = IMAGE_HEADER_SIZE + TEST_PAYLOAD_SIZE;
|
||||
|
||||
(void)drv;
|
||||
image = (part == BOOT_PART_B) ? part_b_image : part_a_image;
|
||||
if ((off > max) || (sz > (max - off)))
|
||||
return -1;
|
||||
memcpy(buf, image + off, (size_t)sz);
|
||||
return (int)sz;
|
||||
}
|
||||
|
||||
uint32_t wolfBoot_get_blob_version(uint8_t *blob)
|
||||
{
|
||||
uint8_t *p = blob + IMAGE_HEADER_OFFSET;
|
||||
uint8_t *end = blob + IMAGE_HEADER_SIZE;
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t version = 0;
|
||||
|
||||
while (((uintptr_t)p + 4) <= (uintptr_t)end) {
|
||||
type = (uint16_t)(p[0] | (p[1] << 8));
|
||||
if (type == 0)
|
||||
break;
|
||||
len = (uint16_t)(p[2] | (p[3] << 8));
|
||||
if (type == HDR_VERSION) {
|
||||
memcpy(&version, p + 4, sizeof(version));
|
||||
break;
|
||||
}
|
||||
p += 4 + len;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
int wolfBoot_open_image_address(struct wolfBoot_image* img, uint8_t* image)
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t fw_size;
|
||||
|
||||
memcpy(&magic, image, sizeof(magic));
|
||||
if (magic != WOLFBOOT_MAGIC)
|
||||
return -1;
|
||||
memset(img, 0, sizeof(*img));
|
||||
img->hdr = image;
|
||||
memcpy(&fw_size, image + sizeof(uint32_t), sizeof(fw_size));
|
||||
img->fw_size = fw_size;
|
||||
img->fw_base = image + IMAGE_HEADER_SIZE;
|
||||
img->hdr_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wolfBoot_verify_integrity(struct wolfBoot_image* img)
|
||||
{
|
||||
img->sha_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wolfBoot_verify_authenticity(struct wolfBoot_image* img)
|
||||
{
|
||||
img->signature_ok = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wolfBoot_get_dts_size(void *dts_addr, uint32_t capacity)
|
||||
{
|
||||
(void)capacity;
|
||||
(void)dts_addr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct stage2_parameter *stage2_get_parameters(void)
|
||||
{
|
||||
return &mock_stage2_params;
|
||||
}
|
||||
|
||||
void x86_log_memory_load(uint32_t start, uint32_t end, const char *name)
|
||||
{
|
||||
(void)start;
|
||||
(void)end;
|
||||
(void)name;
|
||||
}
|
||||
|
||||
void hal_prepare_boot(void)
|
||||
{
|
||||
}
|
||||
|
||||
int hal_flash_protect(haladdr_t address, int len)
|
||||
{
|
||||
(void)address;
|
||||
(void)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void do_boot(const uint32_t *address)
|
||||
{
|
||||
mock_do_boot_called++;
|
||||
mock_boot_address = address;
|
||||
}
|
||||
|
||||
#include "update_disk.c"
|
||||
|
||||
/* --- tests ---------------------------------------------------------- */
|
||||
|
||||
START_TEST(test_fsp_oversized_slot_falls_back_to_other_slot)
|
||||
{
|
||||
/* Slot A declares a payload that does not fit in low memory; slot B
|
||||
* holds a good image. Boot must continue with B instead of aborting. */
|
||||
reset_mocks();
|
||||
build_image(part_a_image, 7, TEST_PAYLOAD_SIZE * 2, 0xA1);
|
||||
build_image(part_b_image, 7, TEST_PAYLOAD_SIZE, 0xB2);
|
||||
|
||||
wolfBoot_start();
|
||||
|
||||
ck_assert_int_eq(wolfBoot_panicked, 0);
|
||||
ck_assert_int_eq(mock_do_boot_called, 1);
|
||||
ck_assert_ptr_eq(mock_boot_address, (const uint32_t *)WOLFBOOT_LOAD_ADDRESS);
|
||||
ck_assert_int_eq(memcmp(load_buffer, part_b_image + IMAGE_HEADER_SIZE,
|
||||
TEST_PAYLOAD_SIZE), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_fsp_both_slots_oversized_panics)
|
||||
{
|
||||
/* Neither slot fits: the retry loop must exhaust and panic. */
|
||||
reset_mocks();
|
||||
build_image(part_a_image, 7, TEST_PAYLOAD_SIZE * 2, 0xA1);
|
||||
build_image(part_b_image, 7, TEST_PAYLOAD_SIZE * 2, 0xB2);
|
||||
|
||||
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. */
|
||||
reset_mocks();
|
||||
|
||||
wolfBoot_start();
|
||||
|
||||
ck_assert_int_eq(wolfBoot_panicked, 0);
|
||||
ck_assert_int_eq(mock_do_boot_called, 1);
|
||||
ck_assert_ptr_eq(mock_boot_address, (const uint32_t *)WOLFBOOT_LOAD_ADDRESS);
|
||||
ck_assert_int_eq(memcmp(load_buffer, part_a_image + IMAGE_HEADER_SIZE,
|
||||
TEST_PAYLOAD_SIZE), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *wolfboot_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("wolfBoot");
|
||||
TCase *tc = tcase_create("update-disk-fsp");
|
||||
|
||||
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_fitting_slot_boots);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fails;
|
||||
Suite *s = wolfboot_suite();
|
||||
SRunner *sr = srunner_create(s);
|
||||
|
||||
srunner_run_all(sr, CK_NORMAL);
|
||||
fails = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
return fails;
|
||||
}
|
||||
Loading…
Reference in New Issue