diff --git a/src/delta.c b/src/delta.c index 236a6c09..67c44e5f 100644 --- a/src/delta.c +++ b/src/delta.c @@ -303,6 +303,15 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len) blk_start = pa - ctx->src_a; if (blk_start > BLOCK_OFF_MAX) return -1; + if (((blk_start >> 16) & 0xFF) == ESC) { + /* The most-significant offset byte would collide with + * the escaped-literal marker (ESC ESC), making the + * header indistinguishable from a literal ESC byte on + * decode. Skip this candidate and keep searching. + */ + pa++; + continue; + } b_start = ctx->off_b; pa+= BLOCK_HDR_SIZE; ctx->off_b += BLOCK_HDR_SIZE; @@ -367,6 +376,13 @@ int wb_diff(WB_DIFF_CTX *ctx, uint8_t *patch, uint32_t len) blk_start = pb - ctx->src_b; if (blk_start > BLOCK_OFF_MAX) return -1; + if (((blk_start >> 16) & 0xFF) == ESC) { + /* Same ESC-collision hazard as the forward-match + * path: skip this candidate and keep searching. + */ + pb++; + continue; + } pb+= BLOCK_HDR_SIZE; ctx->off_b += BLOCK_HDR_SIZE; while ((pb < pb_limit) && diff --git a/tools/unit-tests/unit-delta.c b/tools/unit-tests/unit-delta.c index b870b32c..6f630ac4 100644 --- a/tools/unit-tests/unit-delta.c +++ b/tools/unit-tests/unit-delta.c @@ -533,6 +533,34 @@ START_TEST(test_wb_patch_and_diff_multi_sector_images) } END_TEST +START_TEST(test_wb_patch_and_diff_match_offset_msb_equals_esc) +{ + /* A matched block whose 24-bit source offset has 0x7f (ESC) as its + * most-significant byte would encode a header starting with the same + * two bytes (ESC, ESC) used to escape a literal ESC byte, making it + * indistinguishable on decode. wb_diff must never emit such a header; + * base images large enough to expose an offset in [0x7f0000,0x7fffff] + * are a supported configuration (e.g. MMU/Linux delta updates). + */ + static uint8_t src_a[0x800000]; + uint8_t src_b[7]; + const uint32_t src_off = 0x7f0010; + + memset(src_a, 0, sizeof(src_a)); + src_a[src_off] = 0x11; + src_a[src_off + 1] = 0x22; + src_a[src_off + 2] = 0x33; + src_a[src_off + 3] = 0x44; + src_a[src_off + 4] = 0x55; + src_a[src_off + 5] = 0x66; + + memcpy(src_b, src_a + src_off, 6); + src_b[6] = 0xAA; + + (void)run_roundtrip_case(src_a, sizeof(src_a), src_b, sizeof(src_b), 64); +} +END_TEST + START_TEST(test_wb_diff_get_sector_size_rejects_values_above_16bit) { #if HAVE_POSIX_FORK @@ -690,6 +718,7 @@ Suite *patch_diff_suite(void) tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff_completely_different_images); tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff_all_escape_images); tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff_multi_sector_images); + tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff_match_offset_msb_equals_esc); tcase_add_test(tc_wolfboot_delta, test_wb_diff_get_sector_size_accepts_16bit_limit); tcase_add_test(tc_wolfboot_delta, test_wb_diff_get_sector_size_rejects_values_above_16bit); tcase_add_test(tc_wolfboot_delta, test_wb_patch_and_diff_size_changing_update);