Files
vt1200/lat/probe/README.md
T

82 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LAT crash probe
Targets the VT1200's LAT receive path, specifically **Finding A** from
`../notes/lat-receive-audit.md`: the demultiplexer at `0x16C44` walks
`nbr_slots` slots with **no length bound**.
## Components
| File | Purpose |
|---|---|
| `lat_probe.py` | crafts a malformed LAT RUN on the wire (standalone; `--dry-run`) |
| `test_lat_probe.py` | unit tests; reconstructs a captured real frame byte-for-byte |
| `run_latd_fuzz.sh` | runs the **patched latd** with the probe armed via `LATD_FUZZ` |
| `extract_stream.py` | pulls the exact host→VT1200 byte stream out of a pcap (self-contained libpcap + LAT parser) |
| `replay_stream.py` | replays that stream to stdout so it can be used as a latd service command; `--limit N` bisects |
| `announce_replay.py` | re-sends the captured LAT **service announcements** (type `0xA`) verbatim, at a chosen interval |
| `heartbeat.sh` | output-producing soak service — so "alive" is distinguishable from a blank idle window |
## New lead (2026-10-15): service announcements
Replaying the data stream from the crash capture does **not** crash the terminal
(see `../../NEXT_SESSION.md`). The one protocol-level difference is that the crash
session also carried **91 LAT service announcements** (message type `0xA`, multicast
to `09:00:2b:00:00:0f`), one every ~10 s — and the audit's **Finding 3** says that path
(LAD update, `0x10660`/`0x103CA`) does `memcpy`s with announcement-derived lengths and
no confirmed upper bound. `announce_replay.py` tests exactly that.
```sh
sudo python3 announce_replay.py ../local/filter-test2.pcap --dry-run
sudo python3 announce_replay.py ../local/filter-test2.pcap --interval 10 --forever
```
Note the 2-byte field at payload offsets 14–15 that changes on every announcement
(`server.cc:221`: `announce->incarnation = --multicast_incarnation;`) — prime suspect.
## The patch to latd
`code/latd/connection.cc` gains `LATConnection::send_fuzz_run()` and a one-shot
hook in `circuit_timer()`:
```cpp
// fires once, on the first circuit-timer tick of a live circuit
if (fuzz_claimed > 0 && !fuzz_done) { fuzz_done = true; send_fuzz_run(n); }
```
`send_fuzz_run()` builds the LAT header by hand and sets `num_slots = n` while
appending exactly one 4-byte Data_a slot — i.e. it lies about the slot count,
which is precisely what the firmware fails to check. It uses the connection's
own `local_connid`/`remote_connid`, sequence number and socket, so the frame is
valid on the live circuit (no need to guess negotiated circuit IDs).
## Procedure
1. Power-cycle the VT1200 (a crash leaves it faulted).
2. Build: `make -C ../local/build -j8`
3. Arm and run (needs root for AF_PACKET):
```sh
sudo LATD_FUZZ=255 ../local/build/latd -d -v -ienp197s0f3u1 -s<service> -lestderr
```
or `./run_latd_fuzz.sh -d -v -ienp197s0f3u1 -s<service> -lestderr`
4. Have the terminal connect (log in) — the probe fires on the first circuit
timer after the circuit is up.
5. Watch the terminal for a Level-0 fault, and `tcpdump` for the frame.
Standalone (no latd) alternative, once you know the live circuit IDs:
```sh
python3 lat_probe.py --dst-cir 0x0001 --src-cir 0x5460 --nbr-slots 255 --dry-run
sudo python3 lat_probe.py --nbr-slots 255 --count 3
```
## Status
The Finding-A fuzz probe (`lat_probe.py` / `LATD_FUZZ`) is still **not fired at
hardware** — deliberately, until the demux walk is understood, so a crash can be
*interpreted* rather than merely observed.
The **stream replay** route was fired, and is negative: the exact byte stream that
accompanied the crash does not crash the terminal. The **announcement soak**
(`announce_replay.py`, or latd's own announcements with `latcp -m 10`) is the current
test — see `../../NEXT_SESSION.md` for the armed procedure and the bisect plan.