fix(micromate): the 0x5A chunk offset is a uint32 -- a 64 KB cap was one event away
UM20147 holds a 72,560-byte event. chunk_params() wrote the offset as a uint16 at params[2:4], because every offset THOR was observed to send fits in two bytes (largest 0x3400 = 13,312), which caps a download at 65,536 B -- so that event could not have been fetched at all. params[0:4] is demonstrably ONE 4-byte field: chunk 0 puts the 4-byte event key there. Writing the offset as a uint32 BE in the same slot is BYTE-IDENTICAL for every offset below 65,536, so nothing verified against THOR's 74 captured frames changes -- the replay test still matches all of them -- and the range extends to 4 GB. Above 64 KB this is inference and the docstring says so: the field's width is established, the device's handling of a non-zero high byte is not. Also newly reachable: at offset 1 MiB params[1] is 0x10, which must go out as `10 10`. Nothing below 64 KB can produce that, so the uint32 change is what first makes the case possible -- and an unescaped 0x10 in 5A params is the exact bug that cost the Series III walk a release. Tested. THIS IS THE SERIES III 64 KB PAGE-BOUNDARY BUG WEARING A DIFFERENT HAT. There, parse_strt_end_offset() discards the key's page byte and the walk crashes once a unit's buffer crosses 64 KB; that one is still open. The transferable lesson: an address field whose high bytes are zero in every capture is not a narrow field, it is an untested one. Same mistake, found twice, in code written years apart. Confirmed in the same run: 0x06 content[0:4] IS the event count -- UM20147 holds 5 events and reads 5, making it three for three across both firmware lines (0->0, 6->6, 5->5). And content[4:8] is a CONSTANT, not a count: it reads 9 on a unit with 6 events and on a unit with 5. list_events() still walks to the sentinel; the count is worth adopting as a pre-check, not a replacement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
@@ -994,6 +994,37 @@ its counter resets, so keys are reused *within* a unit, which is why
|
||||
`ach_state.json` tracks `max_downloaded_key` per serial. Series IV inherits that
|
||||
and adds cross-unit collision on top.
|
||||
|
||||
### ⚠ 🔑 The chunk offset is a uint32 — and a 64 KB cap was one event away
|
||||
|
||||
UM20147 holds a **72,560-byte** event (`055d4a83`). The `0x5A` chunk offset was
|
||||
implemented as a **uint16 at `params[2:4]`**, because every offset THOR was
|
||||
observed to send fits in two bytes — the largest is `0x3400` (13,312). That caps
|
||||
a download at **65,536 bytes**, so that event could not have been fetched at all.
|
||||
|
||||
`params[0:4]` is demonstrably **one 4-byte field**: chunk 0 puts the 4-byte event
|
||||
key there. Writing the offset as a uint32 BE in the same slot is **byte-identical
|
||||
for every offset below 65,536** — so it changes nothing that was verified against
|
||||
THOR's 74 captured frames — and extends the range to 4 GB.
|
||||
|
||||
⚠ **Above 64 KB this is inference.** No capture exercises a carry into
|
||||
`params[1]`. The field's width is established; the device's handling of a
|
||||
non-zero high byte is not.
|
||||
|
||||
⚠ **At offset 1 MiB `params[1]` is `0x10`**, which must be escaped on the wire as
|
||||
`10 10`. Unreachable below 64 KB, so the uint32 change is what first makes that
|
||||
case possible — and an unescaped `0x10` in `5A` params is the exact bug that cost
|
||||
the Series III walk a release.
|
||||
|
||||
**This is the Series III 64 KB page-boundary bug wearing a different hat.** There,
|
||||
`parse_strt_end_offset()` discards the key's page byte and the walk crashes once a
|
||||
unit's buffer crosses 64 KB; that is **still open**. The transferable lesson:
|
||||
*an address field whose high bytes are zero in every capture is not a narrow
|
||||
field, it is an untested one.* Both bugs are the same mistake, found twice, in
|
||||
code written years apart.
|
||||
|
||||
**The test is sitting on a desk:** download `055d4a83` from UM20147 and see
|
||||
whether 71 chunks come back.
|
||||
|
||||
### Still not covered
|
||||
- **A unit that is monitoring**, and a unit with a nearly-full event buffer.
|
||||
- **The inbound call-home session** — still the one protocol unknown.
|
||||
|
||||
Reference in New Issue
Block a user