Skip to content

Commit 6ba2172

Browse files
bigbrettdanielinux
authored andcommitted
Add additional test coverage for monolithic self updates with asymmetric partition sizing
1 parent 25aa151 commit 6ba2172

3 files changed

Lines changed: 72 additions & 0 deletions

File tree

.github/workflows/test-sim-self-update.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,28 @@ jobs:
3838
cp config/examples/sim-self-update-monolithic.config .config
3939
make test-sim-self-update-monolithic
4040
41+
# Shrink BOOT below the payload size so staging only works because the
42+
# UPDATE partition is sized independently (WOLFBOOT_PARTITION_UPDATE_SIZE)
43+
- name: Run monolithic self-update test (payload exceeds a BOOT-sized slot)
44+
run: |
45+
make clean
46+
cp config/examples/sim-self-update-monolithic.config .config
47+
make test-sim-self-update-monolithic WOLFBOOT_PARTITION_SIZE=0x30000 WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x50000
48+
49+
# Unset WOLFBOOT_PARTITION_UPDATE_SIZE so it falls back to
50+
# WOLFBOOT_PARTITION_SIZE, restoring the legacy symmetric layout
51+
- name: Run monolithic self-update test (legacy symmetric layout)
52+
run: |
53+
make clean
54+
cp config/examples/sim-self-update-monolithic.config .config
55+
make test-sim-self-update-monolithic WOLFBOOT_PARTITION_SIZE=0x80000 WOLFBOOT_PARTITION_UPDATE_SIZE= WOLFBOOT_PARTITION_UPDATE_ADDRESS=0xA0000
56+
57+
- name: Run monolithic self-update oversize rejection test
58+
run: |
59+
make clean
60+
cp config/examples/sim-self-update-monolithic.config .config
61+
make test-sim-self-update-monolithic-oversize
62+
4163
- name: Run self-header verification test (internal flash)
4264
run: |
4365
make clean
@@ -50,6 +72,9 @@ jobs:
5072
cp config/examples/sim-self-header-ext.config .config
5173
make test-sim-self-header-ext-verify
5274
75+
# With WOLFBOOT_SELF_HEADER=1 the app grows enough that the payload
76+
# exceeds what a BOOT-sized slot could stage, so this step also covers
77+
# asymmetric staging capacity
5378
- name: Run combined monolithic self-update + self-header test
5479
run: |
5580
make clean

docs/firmware_update.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ make clean && make
386386
make test-sim-self-update-monolithic
387387
```
388388

389+
A companion negative test, `test-sim-self-update-monolithic-oversize`, stages a
390+
signed payload larger than the install span and verifies that wolfBoot refuses
391+
it without touching the bootloader or the BOOT partition.
392+
389393
#### Skipping boot image verification
390394

391395
When wolfBoot is used together with the [self-header](#self-header-persisting-the-bootloader-manifest)

tools/test.mk

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,49 @@ test-sim-self-update-monolithic-self-header: wolfboot.bin test-app/image_v1_sign
343343
@echo " Self-header persisted correctly: PASSED"
344344
@echo "=== Monolithic Self-Update + Self-Header Test PASSED ==="
345345

346+
# Test that an oversized monolithic self-update is rejected. The payload is
347+
# signed and staged normally, but its firmware size exceeds the install span
348+
# (bootloader region + BOOT partition minus the trailer sector), so wolfBoot
349+
# must refuse it and leave the bootloader and BOOT partition untouched.
350+
# Requires a build with wolfBoot_printf output (e.g. DEBUG=1, as in the
351+
# sim-self-update-monolithic example config).
352+
test-sim-self-update-monolithic-oversize: wolfboot.bin test-app/image_v1_signed.bin FORCE
353+
@echo "=== Simulator Monolithic Self-Update Oversize Rejection Test ==="
354+
@# Create dummy bootloader (0xAA pattern, exactly bootloader region size)
355+
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) count=1 2>/dev/null | tr '\000' '\252' > monolithic_dummy_bl.bin
356+
@# Build a payload 0x100 bytes past the max install span, padded with 0xFF.
357+
@# It still fits the UPDATE partition, so only the install-span check can
358+
@# reject it.
359+
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET) + $(WOLFBOOT_PARTITION_SIZE) - $(WOLFBOOT_SECTOR_SIZE) + 0x100)) count=1 2>/dev/null | tr '\000' '\377' > monolithic_oversize.bin
360+
$(Q)cat monolithic_dummy_bl.bin test-app/image_v1_signed.bin | dd of=monolithic_oversize.bin conv=notrunc 2>/dev/null
361+
@# Sign with an inflated update partition size: the keytool refuses
362+
@# oversized images, and the point here is the bootloader's own guard
363+
$(Q)$(SIGN_ENV) WOLFBOOT_PARTITION_UPDATE_SIZE=0x1000000 $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update monolithic_oversize.bin $(PRIVATE_KEY) 2
364+
@# Create update partition with signed oversized image and "pBOOT" trailer
365+
$(Q)dd if=/dev/zero bs=$$(($(or $(WOLFBOOT_PARTITION_UPDATE_SIZE),$(WOLFBOOT_PARTITION_SIZE)))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd
366+
$(Q)dd if=monolithic_oversize_v2_signed.bin of=update_part.dd bs=1 conv=notrunc
367+
$(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(or $(WOLFBOOT_PARTITION_UPDATE_SIZE),$(WOLFBOOT_PARTITION_SIZE)) - 5)) conv=notrunc
368+
@# Create erased boot partition
369+
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd
370+
@# Assemble flash: wolfboot.bin at 0, empty boot partition, update partition
371+
$(Q)$(BINASSEMBLE) internal_flash.dd \
372+
0 wolfboot.bin \
373+
$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) boot_part.dd \
374+
$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS) - $(ARCH_FLASH_OFFSET))) update_part.dd
375+
@# Run simulator - the self-update must be refused before any flash write
376+
$(Q)./wolfboot.elf get_version > monolithic_oversize.log 2>&1 || true
377+
$(Q)grep -q "Self update image too large" monolithic_oversize.log || \
378+
{ echo "Rejection message not found; simulator output:"; \
379+
cat monolithic_oversize.log; false; }
380+
@echo " Oversized self-update rejected: PASSED"
381+
@# Verify the bootloader region still contains the original wolfboot.bin
382+
$(Q)cmp -n $$(wc -c < wolfboot.bin | awk '{print $$1}') wolfboot.bin internal_flash.dd
383+
@echo " Bootloader region untouched: PASSED"
384+
@# Verify the boot partition is still fully erased
385+
$(Q)cmp -n $$(($(WOLFBOOT_PARTITION_SIZE))) boot_part.dd internal_flash.dd 0 $$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET)))
386+
@echo " Boot partition untouched: PASSED"
387+
@echo "=== Monolithic Self-Update Oversize Rejection Test PASSED ==="
388+
346389
# Test self-header cryptographic verification (hash + signature validation)
347390
#
348391
# Verifies that an application can cryptographically verify the bootloader using

0 commit comments

Comments
 (0)