mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-31 12:05:05 +02:00
82 lines
3.7 KiB
Markdown
82 lines
3.7 KiB
Markdown
# 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.
|