Summary
stage0/jump_stage1.c hashes stage-1 from flash before jumping to it (EBLDR_VERIFY_STAGE1), but the loop discards eos_hal_flash_read()'s return value:
eos_hal_flash_read(stage1_addr + off, buf, chunk);
eos_sha256_update(&sha_ctx, buf, chunk);
A read that fails leaves buf holding the previous chunk — or, on the first iteration, whatever the stack held — and that is hashed as if it were stage-1. The mismatch that follows sends the device to recovery, so the outcome is fail-closed by accident, and it is logged as 0xBAD1 (hash mismatch), which is not what happened. core/crypto_boot.c's eos_crypto_verify_image() does the same job and refuses a failed read; this is the same class as #38 (eos_crc32() returning 0 on a failed read).
Fix
PR to follow: test the read, enter recovery with its own reason (0xBAD2) and return; plus a source-level guard (stage-0 only compiles in a cross build) that every HAL read/write in stage0/ examines its result.
Summary
stage0/jump_stage1.chashes stage-1 from flash before jumping to it (EBLDR_VERIFY_STAGE1), but the loop discardseos_hal_flash_read()'s return value:A read that fails leaves
bufholding the previous chunk — or, on the first iteration, whatever the stack held — and that is hashed as if it were stage-1. The mismatch that follows sends the device to recovery, so the outcome is fail-closed by accident, and it is logged as0xBAD1(hash mismatch), which is not what happened.core/crypto_boot.c'seos_crypto_verify_image()does the same job and refuses a failed read; this is the same class as #38 (eos_crc32()returning 0 on a failed read).Fix
PR to follow: test the read, enter recovery with its own reason (
0xBAD2) and return; plus a source-level guard (stage-0 only compiles in a cross build) that every HAL read/write instage0/examines its result.