From 96228bdd255072853d04fba9a86557f097cd739a Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Tue, 24 Feb 2026 10:51:11 +0100 Subject: [PATCH 1/4] Added boundary checks for delta image --- src/delta.c | 6 +++++ tools/unit-tests/unit-delta.c | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/delta.c b/src/delta.c index 878f85ca1d..a4415da048 100644 --- a/src/delta.c +++ b/src/delta.c @@ -118,6 +118,9 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) sz = ctx->blk_sz; if (sz > len) sz = len; + if (ctx->blk_off > ctx->src_size || + sz > ctx->src_size - ctx->blk_off) + return -1; memcpy(dst + dst_off, ctx->src_base + ctx->blk_off, sz); if (ctx->blk_sz > len) { ctx->blk_sz -= len; @@ -150,6 +153,9 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) } else { copy_sz = sz; } + if (src_off > ctx->src_size || + copy_sz > ctx->src_size - src_off) + return -1; memcpy(dst + dst_off, ctx->src_base + src_off, copy_sz); if (sz == copy_sz) { /* End of the block, reset counters and matching state */ diff --git a/tools/unit-tests/unit-delta.c b/tools/unit-tests/unit-delta.c index c384784b87..30fbe7245b 100644 --- a/tools/unit-tests/unit-delta.c +++ b/tools/unit-tests/unit-delta.c @@ -48,6 +48,49 @@ START_TEST(test_wb_patch_init_invalid) } END_TEST +START_TEST(test_wb_patch_src_bounds_invalid) +{ + WB_PATCH_CTX patch_ctx; + uint8_t src[SRC_SIZE] = {0}; + uint8_t patch[PATCH_SIZE] = {0}; + uint8_t dst[DELTA_BLOCK_SIZE] = {0}; + int ret; + + /* ESC + header with src_off beyond src_size */ + patch[0] = ESC; + patch[1] = 0x00; /* off[0] */ + patch[2] = 0x10; /* off[1] -> 0x001000 */ + patch[3] = 0x00; /* off[2] */ + patch[4] = 0x00; /* sz[0] */ + patch[5] = 0x10; /* sz[1] -> 16 */ + + ret = wb_patch_init(&patch_ctx, src, SRC_SIZE, patch, BLOCK_HDR_SIZE); + ck_assert_int_eq(ret, 0); + + ret = wb_patch(&patch_ctx, dst, sizeof(dst)); + ck_assert_int_eq(ret, -1); +} +END_TEST + +START_TEST(test_wb_patch_resume_bounds_invalid) +{ + WB_PATCH_CTX patch_ctx; + uint8_t src[SRC_SIZE] = {0}; + uint8_t patch[PATCH_SIZE] = {0}; + uint8_t dst[DELTA_BLOCK_SIZE] = {0}; + int ret; + + ret = wb_patch_init(&patch_ctx, src, SRC_SIZE, patch, BLOCK_HDR_SIZE); + ck_assert_int_eq(ret, 0); + + patch_ctx.matching = 1; + patch_ctx.blk_off = SRC_SIZE + 1; + patch_ctx.blk_sz = 4; + + ret = wb_patch(&patch_ctx, dst, sizeof(dst)); + ck_assert_int_eq(ret, -1); +} +END_TEST START_TEST(test_wb_diff_init_invalid) { @@ -162,6 +205,8 @@ Suite *patch_diff_suite(void) tcase_add_test(tc_wolfboot_delta, test_wb_patch_init_invalid); tcase_add_test(tc_wolfboot_delta, test_wb_diff_init_invalid); + tcase_add_test(tc_wolfboot_delta, test_wb_patch_src_bounds_invalid); + tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_bounds_invalid); tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff); suite_add_tcase(s, tc_wolfboot_delta); From b1805740970baea9936ffe8f90b96f2a1674233b Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Tue, 24 Feb 2026 14:19:22 +0100 Subject: [PATCH 2/4] Addressed copilot's comments --- src/delta.c | 19 ++++++++++--------- tools/unit-tests/unit-delta.c | 27 +++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/delta.c b/src/delta.c index a4415da048..dfeb10db6e 100644 --- a/src/delta.c +++ b/src/delta.c @@ -106,6 +106,7 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) uint32_t src_off; uint16_t sz; uint32_t copy_sz; + uint32_t resume_sz; if (!ctx) return -1; if (len < BLOCK_HDR_SIZE) @@ -115,13 +116,13 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) uint8_t *pp = patch_read_cache(ctx); if (ctx->matching) { /* Resume matching block from previous sector */ - sz = ctx->blk_sz; - if (sz > len) - sz = len; + resume_sz = ctx->blk_sz; + if (resume_sz > len) + resume_sz = len; if (ctx->blk_off > ctx->src_size || - sz > ctx->src_size - ctx->blk_off) + resume_sz > ctx->src_size - ctx->blk_off) return -1; - memcpy(dst + dst_off, ctx->src_base + ctx->blk_off, sz); + memcpy(dst + dst_off, ctx->src_base + ctx->blk_off, resume_sz); if (ctx->blk_sz > len) { ctx->blk_sz -= len; ctx->blk_off += len; @@ -130,7 +131,7 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) ctx->blk_sz = 0; ctx->matching = 0; } - dst_off += sz; + dst_off += resume_sz; continue; } if (*pp == ESC) { @@ -145,6 +146,9 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) src_off = (hdr->off[0] << 16) + (hdr->off[1] << 8) + hdr->off[2]; sz = (hdr->sz[0] << 8) + hdr->sz[1]; + if (src_off > ctx->src_size || + sz > ctx->src_size - src_off) + return -1; ctx->matching = 1; if (sz > (len - dst_off)) { copy_sz = len - dst_off; @@ -153,9 +157,6 @@ int wb_patch(WB_PATCH_CTX *ctx, uint8_t *dst, uint32_t len) } else { copy_sz = sz; } - if (src_off > ctx->src_size || - copy_sz > ctx->src_size - src_off) - return -1; memcpy(dst + dst_off, ctx->src_base + src_off, copy_sz); if (sz == copy_sz) { /* End of the block, reset counters and matching state */ diff --git a/tools/unit-tests/unit-delta.c b/tools/unit-tests/unit-delta.c index 30fbe7245b..5dd6af7623 100644 --- a/tools/unit-tests/unit-delta.c +++ b/tools/unit-tests/unit-delta.c @@ -59,8 +59,8 @@ START_TEST(test_wb_patch_src_bounds_invalid) /* ESC + header with src_off beyond src_size */ patch[0] = ESC; patch[1] = 0x00; /* off[0] */ - patch[2] = 0x10; /* off[1] -> 0x001000 */ - patch[3] = 0x00; /* off[2] */ + patch[2] = 0x10; /* off[1] -> 0x0010FF */ + patch[3] = 0xFF; /* off[2] */ patch[4] = 0x00; /* sz[0] */ patch[5] = 0x10; /* sz[1] -> 16 */ @@ -92,6 +92,28 @@ START_TEST(test_wb_patch_resume_bounds_invalid) } END_TEST +START_TEST(test_wb_patch_resume_large_len) +{ + WB_PATCH_CTX patch_ctx; + uint8_t src[SRC_SIZE] = {0}; + uint8_t patch[PATCH_SIZE] = {0}; + uint8_t dst[DST_SIZE] = {0}; + uint32_t len = 70000; + int ret; + + src[0] = 0xA5; + ret = wb_patch_init(&patch_ctx, src, SRC_SIZE, patch, BLOCK_HDR_SIZE); + ck_assert_int_eq(ret, 0); + + patch_ctx.matching = 1; + patch_ctx.blk_off = 0; + patch_ctx.blk_sz = 70000; + + ret = wb_patch(&patch_ctx, dst, len); + ck_assert_int_eq(ret, -1); +} +END_TEST + START_TEST(test_wb_diff_init_invalid) { WB_DIFF_CTX ctx; @@ -207,6 +229,7 @@ Suite *patch_diff_suite(void) tcase_add_test(tc_wolfboot_delta, test_wb_diff_init_invalid); tcase_add_test(tc_wolfboot_delta, test_wb_patch_src_bounds_invalid); tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_bounds_invalid); + tcase_add_test(tc_wolfboot_delta, test_wb_patch_resume_large_len); tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff); suite_add_tcase(s, tc_wolfboot_delta); From a4dc9c358f27ff180099a19979a1426eead8354c Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Tue, 24 Feb 2026 16:17:45 +0100 Subject: [PATCH 3/4] Use partition size as bound if header sector is erased --- src/update_flash.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/update_flash.c b/src/update_flash.c index 0524f4b4de..317a9c1b8d 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -441,6 +441,11 @@ static int wolfBoot_delta_update(struct wolfBoot_image *boot, uint16_t base_hash_sz; uint8_t *base_hash; + if (boot->fw_size == 0) { + /* Resume after powerfail can leave boot header erased; bound by partition size. */ + boot->fw_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE; + } + /* Use biggest size for the swap */ total_size = boot->fw_size + IMAGE_HEADER_SIZE; if ((update->fw_size + IMAGE_HEADER_SIZE) > total_size) From c9d94d6a78c309861b856df273b2519f58a21d30 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Tue, 24 Feb 2026 16:30:14 +0100 Subject: [PATCH 4/4] Using 'len' iso magic number 70000 in test --- tools/unit-tests/unit-delta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/unit-tests/unit-delta.c b/tools/unit-tests/unit-delta.c index 5dd6af7623..5c3a2cacb1 100644 --- a/tools/unit-tests/unit-delta.c +++ b/tools/unit-tests/unit-delta.c @@ -107,7 +107,7 @@ START_TEST(test_wb_patch_resume_large_len) patch_ctx.matching = 1; patch_ctx.blk_off = 0; - patch_ctx.blk_sz = 70000; + patch_ctx.blk_sz = len; ret = wb_patch(&patch_ctx, dst, len); ck_assert_int_eq(ret, -1);