Conversation
There was a problem hiding this comment.
Pull request overview
Adds a build option to enable hashing a full image (and header region) in a single hash update call to improve verification performance on memory-mapped/offload-capable platforms.
Changes:
- Introduces
WOLFBOOT_IMG_HASH_ONESHOTbuild flag (config + options) to toggle one-shot hashing. - Updates image hashing paths in
src/image.cto use a singlewc_*Update()call when enabled. - Documents the option and expands CI workflows to build/run simulator tests with the flag enabled.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/config.mk | Adds default value and exposes WOLFBOOT_IMG_HASH_ONESHOT in CONFIG_VARS. |
| options.mk | Maps WOLFBOOT_IMG_HASH_ONESHOT=1 to -DWOLFBOOT_IMG_HASH_ONESHOT. |
| src/image.c | Adds one-shot hashing branches for header/image hashing and flash hashing helpers. |
| docs/compile.md | Documents behavior, constraints, and incompatibility notes for one-shot hashing. |
| .github/workflows/test-sunnyday-simulator.yml | Adds simulator build+run coverage for oneshot + SHA256/SHA384/SHA3. |
| .github/workflows/test-elf-scattered.yml | Adds an ELF_SCATTERED simulator build+run with oneshot enabled. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #736
Scan targets checked: wolfboot-bugs, wolfboot-src
Findings: 3
Medium (2)
Missing bounds guard in ONESHOT header hash allows integer wrap on malformed image
File: src/image.c:990,1093,1202
Function: header_sha256, header_sha384, header_sha3_384
Category: Integer overflows
In the ONESHOT paths of header_sha256, header_sha384, and header_sha3_384, the expression (word32)(end_sha - p) is passed directly to the hash update function without first verifying that end_sha >= p. The original block-by-block code was naturally guarded by the while (p < end_sha) loop condition, which would simply not execute if end_sha <= p. In the ONESHOT path, if a malformed image header causes end_sha to be less than p (e.g., a crafted image where the stored SHA TLV appears at an unexpected offset), the pointer subtraction yields a negative ptrdiff_t which wraps to a very large value when cast to word32. This would cause wc_Sha256Update (and the sha384/sha3 variants) to read far beyond the intended buffer, potentially crashing the bootloader or causing a denial-of-service during firmware verification.
#ifdef WOLFBOOT_IMG_HASH_ONESHOT
wc_Sha256Update(sha256_ctx, p, (word32)(end_sha - p));
#else
{
int blksz;
while (p < end_sha) {Recommendation: Add a bounds check before the ONESHOT hash call in all three header hash functions: if (end_sha <= p) return -1; (or return 0; to match the no-data behavior of the original loop). For example:
#ifdef WOLFBOOT_IMG_HASH_ONESHOT
if (end_sha <= p)
return -1;
wc_Sha256Update(sha256_ctx, p, (word32)(end_sha - p));
#elseONESHOT update_hash_flash_addr silently ignores src_ext flag with no compile-time guard
File: src/image.c:1803-1806
Function: update_hash_flash_addr
Category: Flash manipulation
When WOLFBOOT_IMG_HASH_ONESHOT is defined, update_hash_flash_addr casts addr to (uint8_t*) and dereferences it for size bytes, while discarding src_ext with (void)src_ext. The src_ext parameter indicates whether the address resides in external (non-memory-mapped) flash. If a user misconfigures the build by enabling both WOLFBOOT_IMG_HASH_ONESHOT=1 and EXT_FLASH=1, this function will attempt to directly dereference an external flash address as a memory pointer, leading to a hard fault, reading from an unintended memory region, or computing an incorrect hash — any of which could compromise the boot verification process. While the documentation warns against this combination, there is no #if defined(WOLFBOOT_IMG_HASH_ONESHOT) && defined(EXT_FLASH) #error ... #endif compile-time guard to enforce it.
#ifdef WOLFBOOT_IMG_HASH_ONESHOT
(void)src_ext;
update_hash(ctx, (uint8_t*)addr, size);
return 0;
#elseRecommendation: Add a compile-time guard in src/image.c (or in options.mk) to prevent the incompatible configuration:
#if defined(WOLFBOOT_IMG_HASH_ONESHOT) && defined(EXT_FLASH)
#error "WOLFBOOT_IMG_HASH_ONESHOT is incompatible with EXT_FLASH"
#endifAlternatively, in options.mk:
ifeq ($(WOLFBOOT_IMG_HASH_ONESHOT),1)
ifeq ($(EXT_FLASH),1)
$(error WOLFBOOT_IMG_HASH_ONESHOT is incompatible with EXT_FLASH)
endif
CFLAGS+=-DWOLFBOOT_IMG_HASH_ONESHOT
endifLow (1)
ONESHOT image hash paths skip NULL check on fw_base
File: src/image.c:1016,1122,1230
Function: image_sha256, image_sha384, image_sha3_384
Category: NULL pointer dereference
In the ONESHOT paths of image_sha256, image_sha384, and image_sha3_384, img->fw_base is passed directly to the hash update function (e.g., wc_Sha256Update(&sha256_ctx, img->fw_base, img->fw_size)). The original block-by-block code retrieved the data pointer via get_sha_block(img, position) and checked if (p == NULL) break;, which provided a safety net if the firmware base was not accessible. The ONESHOT path has no equivalent NULL check on img->fw_base. While img itself is checked in the preceding header_sha* call, img->fw_base could be NULL if the image metadata was initialized but the firmware was not memory-mapped, potentially causing a NULL pointer dereference.
#ifdef WOLFBOOT_IMG_HASH_ONESHOT
wc_Sha256Update(&sha256_ctx, img->fw_base, img->fw_size);
#else
{
uint32_t position = 0;
uint8_t* p;
int blksz;
do {
p = get_sha_block(img, position);
if (p == NULL)
break;Recommendation: Add a NULL check on img->fw_base before the ONESHOT hash call in all three image hash functions:
#ifdef WOLFBOOT_IMG_HASH_ONESHOT
if (img->fw_base == NULL)
return -1;
wc_Sha256Update(&sha256_ctx, img->fw_base, img->fw_size);
#elseThis review was generated automatically by Fenrir. Findings are non-blocking.
|
Addressed Fenrir pointer validation concerns. Wontfix compile-time check against |
Adds build option to enable hashing an entire image in one update call, which can dramatically speed up performance on platforms that can support it (memory mapped flash or wolfHSM client offload with DMA).
Deliberately did not make this incompatible at compile time with
EXT_FLASHto prevent interfering with "off-label usage" ofEXT_FLASHby some HALs (for example, used for flash read indirection only in certain cases on TC3xx), however the logical incompatibility of the two is clearly stated in the documentation.