You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
UART recovery: an unprovisioned secret authenticates, and a write into an unmapped slot lands at a flash address #126
Two wire-facing checks in core/recovery.c are weaker than the code around them says.
An unprovisioned recovery secret authenticates anyone.recovery_handle_auth() reads the shared secret from OTP offset 0x180 and compares the client's response against SHA-256(challenge || secret) without looking at what the secret is. Unprogrammed fuses read back as all zeros or all ones — both public — so a device whose recovery secret was never provisioned authenticates any client that sends SHA-256(challenge || 00…00). The keystore already refuses an all-zero key for exactly this reason (core/keystore.c). Verified in the recovery test harness: with a simulated OTP returning zeros, the exchange is ACKed and a WRITE goes through. Latent on shipped boards (none provides otp_read, so authentication always fails there); the first board port with OTP would ship it.
A write into an unmapped slot lands at a flash address.recovery_handle_write() stopped calling eos_recovery_write_in_range() — the rule tests/unit/test_recovery.c exercises, which refuses a slot whose base is 0 — in fix: restore eboot_core buildability broken by unresolved merge conflicts #55's replay, and checks offset + len against the slot size inline. For a slot the board leaves unmapped, "write at offset 0x800 of slot B" becomes "write at flash address 0x800". Verified in the harness: the write is ACKed and lands between the boot-control block and its backup.
Fix
PR to follow: refuse both fuse patterns before comparing (branch-free), log a distinct event; make the handler use the shared range rule again; three tests, each shown failing on the unfixed handler.
Activity