armored: harden fw_base against fault injection

pull/816/head
Daniele Lacamera 2026-07-02 20:09:16 +02:00
parent 277cbbe4f8
commit eca9a20b3b
3 changed files with 61 additions and 6 deletions

View File

@ -173,6 +173,7 @@ struct wolfBoot_image {
uint32_t sha_ok;
uint32_t canary_FEEDCAFE;
uint32_t not_sha_ok;
uintptr_t not_fw_base; /* complement of fw_base, for FI hardening */
uint32_t not_ext; /* image is no longer external */
};
@ -229,6 +230,18 @@ static void NOINLINEFUNCTION wolfBoot_image_clear_sha_ok(
img->not_sha_ok = 1UL;
}
/**
* Records the image entry base together with its complement, so that a single
* fault on the pointer that do_boot() jumps through can be detected by
* FW_BASE_SANITY_CHECK() before the branch is taken.
*/
static void NOINLINEFUNCTION wolfBoot_image_set_fw_base(
struct wolfBoot_image *img, void *base)
{
img->fw_base = (uint8_t *)base;
img->not_fw_base = ~(uintptr_t)base;
}
/**
* Final sanity check, performed just before do_boot, or before starting an
* update that has been verified.
@ -757,6 +770,40 @@ static void NOINLINEFUNCTION wolfBoot_image_clear_sha_ok(
asm volatile("cmp r2, #0xFFFFFFFE":::"cc"); \
asm volatile("bne .-12")
/**
* Hardened assertion that the image entry base is consistent with its stored
* complement (fw_base == ~not_fw_base), performed immediately before do_boot()
* dereferences fw_base. A single fault on either the pointer or the loads
* fails the check safely (spins) instead of redirecting the boot jump.
*/
#define FW_BASE_SANITY_CHECK(p) \
/* Redundant set of r2=0 */ \
asm volatile("mov r2, #0":::"r2"); \
asm volatile("mov r2, #0":::"r2"); \
asm volatile("mov r2, #0":::"r2"); \
asm volatile("mov r2, #0":::"r2"); \
asm volatile("mov r2, #0":::"r2"); \
/* r2 = fw_base, r0 = ~not_fw_base (== expected fw_base) */ \
asm volatile("mov r2, %0" ::"r"((uintptr_t)(p)->fw_base):"r2"); \
asm volatile("mov r0, %0" ::"r"((p)->not_fw_base):"r0"); \
asm volatile("mvn r0, r0":::"r0"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("bne ."); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("bne .-4"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("bne .-8"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("cmp r2, r0":::"cc"); \
asm volatile("bne .-12")
/**
* ECC / Ed / PQ signature verification.
* Those verify functions set an additional value 'p_res'
@ -1521,6 +1568,11 @@ static void UNUSEDFUNCTION wolfBoot_image_clear_sha_ok(
{
img->sha_ok = 0;
}
static void UNUSEDFUNCTION wolfBoot_image_set_fw_base(
struct wolfBoot_image *img, void *base)
{
img->fw_base = (uint8_t *)base;
}
#define likely(x) (x)
#define unlikely(x) (x)
@ -1560,6 +1612,8 @@ static void UNUSEDFUNCTION wolfBoot_image_clear_sha_ok(
if ((p)->sha_ok != 1) \
wolfBoot_panic()
#define FW_BASE_SANITY_CHECK(p) do{} while(0)
#define CONFIRM_MASK_VALID(id, mask) \
if ((mask & (1UL << id)) != (1UL << id)) \
wolfBoot_panic()

View File

@ -1424,7 +1424,7 @@ int wolfBoot_open_image_address(struct wolfBoot_image *img, uint8_t *image)
}
#endif
img->hdr_ok = 1;
img->fw_base = img->hdr + IMAGE_HEADER_SIZE;
wolfBoot_image_set_fw_base(img, img->hdr + IMAGE_HEADER_SIZE);
#ifdef EXT_FLASH
img->hdr_cache = image;
#endif
@ -1488,7 +1488,7 @@ int wolfBoot_open_image(struct wolfBoot_image *img, uint8_t part)
if (part == PART_SWAP) {
img->hdr = (void*)WOLFBOOT_PARTITION_SWAP_ADDRESS;
img->hdr_ok = 1;
img->fw_base = img->hdr;
wolfBoot_image_set_fw_base(img, img->hdr);
img->fw_size = WOLFBOOT_SECTOR_SIZE;
return 0;
}
@ -1507,7 +1507,7 @@ int wolfBoot_open_image(struct wolfBoot_image *img, uint8_t part)
if (ret < 0)
return -1;
img->hdr_ok = 1;
img->fw_base = img->hdr;
wolfBoot_image_set_fw_base(img, img->hdr);
img->fw_size = (uint32_t)ret;
return 0;
}
@ -1620,7 +1620,7 @@ int wolfBoot_open_self_address(struct wolfBoot_image* img, uint8_t* hdr,
return -1;
}
#endif
img->fw_base = image;
wolfBoot_image_set_fw_base(img, image);
img->part = PART_SELF;
img->hdr_ok = 1;

View File

@ -1270,7 +1270,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
wolfBoot_printf(
"Scattered image correctly verified. Setting entry point to %lx\n",
entry);
boot.fw_base = (void*)entry;
wolfBoot_image_set_fw_base(&boot, (void*)entry);
#endif
/* Direct Swap without power fail safety */
@ -1618,7 +1618,7 @@ void RAMFUNCTION wolfBoot_start(void)
wolfBoot_printf(
"Scattered image correctly verified. Setting entry point to %lx\n",
entry);
boot.fw_base = (void*)entry;
wolfBoot_image_set_fw_base(&boot, (void*)entry);
#endif
@ -1650,6 +1650,7 @@ void RAMFUNCTION wolfBoot_start(void)
#endif
#ifndef WOLFBOOT_SKIP_BOOT_VERIFY
PART_SANITY_CHECK(&boot);
FW_BASE_SANITY_CHECK(&boot);
#endif
do_boot((void *)boot.fw_base);
}