# DF-5794 — ttyflush(FREAD|FWRITE) discards the IXOFF resume (VSTART/XON) character

## What

`sys/kern/tty.c` `ttyflush()` (lines 1430-1492). When a tty is input
flow-blocked (`TS_TBLOCK` set because the raw+canonical input queues passed
`t_ihiwat` with `IXOFF`/`CRTS_IFLOW`) and a `FREAD|FWRITE` flush runs
(`ioctl(TIOCFLUSH, FREAD|FWRITE)`, `tcflush(TCIOFLUSH)`, last-close
`ttyclose()` tty.c:254, `ttyrevoke()` tty.c:2822, pty `TIOCREMOTE`/
`TIOCSIG`/master-`TIOCSETA*` paths in tty_pty.c), the FREAD branch calls
`ttyunblock()` (tty.c:1453), which queues the resume character VSTART
(default 0x11/^Q) into `t_outq` (tty.c:1542) and clears `TS_TBLOCK`
(tty.c:1540). The **trailing** `if (rw & FWRITE) FLUSHQ(&tp->t_outq)`
(tty.c:1487-1488) then deletes that character from the freshly emptied
output queue.

Result: the peer that honoured the earlier XOFF (0x13/^S) — a terminal
emulator, a remote tty server, a serial device — is **never told to resume
transmission**, while the kernel state claims it is unblocked (`TS_TBLOCK`
cleared, so neither `ttread`'s low-water `ttyunblock` (tty.c:1936-1939) nor
any other path will re-send XON). The tty input channel is wedged until the
peer independently emits VSTART (e.g. a human presses ^Q at the remote end).

## Reproduce (guest, unprivileged)

```
cd findings/poc/DF-5794
cc -O -o df5794 df5794.c
./df5794
```

Expected (stock kernel):

```
CONTROL: XOFF (0x13) received by master
CONTROL: XON (0x11) after slave read-drain: SEEN (expected)     <- rig sanity
TEST: XOFF (0x13) received by master; TS_TBLOCK set
TEST: TIOCFLUSH(FREAD|FWRITE) done (master pre-drained)
TEST: XON (0x11) after TCIOFLUSH: NOT SEEN => XON discarded ...  <- BUG
RESULT: BUG REPRODUCED (XON discarded by ttyflush)
```

CONTROL arm proves the kernel *does* emit XON via the same `ttyunblock()`
when reached through `ttread`'s low-water path; the TEST arm shows the
flush-ordered call's character is destroyed. 6/6 stock runs reproduced;
with `fix.diff` applied and a rebuilt kernel the TEST arm sees the XON
(`run.fixed.log`), i.e. the defect is gone.

## Files

* `df5794.c` — self-contained pty-pair PoC (no privileges, no pts grant games)
* `run.log`, `run.2.log` — decisive stock-kernel runs
* `run.fixed.log` — patched-kernel run (fix validated)
* `fix.diff` — minimal reorder: move the TS_TBLOCK unblock after the final
  output flush
* `fix_build.log`, `fix_run.log` — single-fix kernel build + rerun evidence
* `env.txt`, `build.log`, `code_hash.txt`
