# DF-2876 — BLK_READ at/after EOF returns stale shared pbuf memory to the
# dmsg peer (cross-process / cross-device kernel-mediated info leak)

## What this pack contains

- `dfpeer.c` — dmsg wire peer (see DF-2875 pack).
- `run_f3.sh` — sets up a vn(4) disk containing 16MB of "secret" pattern,
  seeds the shared pbuf-mem pool by physio (`dd if=/dev/vn0 of=/dev/null`),
  then issues BLK_READ at EOF through the dmsg channel.
- `leak_sample.txt` — the three leak runs + md5s; run 1 returned a
  **full 64KB block identical to the secret image** (md5 7081aa33...),
  run 2 returned the **boot disk's MBR boot code** (`fc 31 c0 8e c0 8e
  d8 8e d0 bc 00 7c...`) through a *different* disk's channel,
  run 3 returned stale dmsg write aux (0xAA fill).
- `fix.diff` — diskiodone READ: on B_ERROR attach no data; on short reads
  attach only completed bytes.

## Root cause

`diskiodone` (sys/kern/subr_diskiocom.c:594-597) sets `data = bp->b_data;
bytes = bp->b_bcount` for BUF_CMD_READ **before** looking at B_ERROR /
b_resid, and unconditionally attaches `bytes` of buffer content to the
reply (:651-655). A read that transfers nothing (EOF: vn's VOP_READ
returns success with untouched uio_resid → b_resid = b_bcount, no
B_ERROR) therefore ships the *previous* contents of the shared
`getpbuf_mem` KVA arena to the peer. That arena is shared with
`kern_physio` (every raw device I/O of every process), disklabel/GPT/MBR
probes, and other dmsg I/Os (sys/vm/vm_pager.c:505, sys/kern/kern_physio.c:43).

## Build & run (root on the DF guest)

```
cc -O -Wall -o /tmp/dfpeer dfpeer.c
sh run_f3.sh
```

## Expected output (stock kernel)

`eofread off=16777216 len=65536 -> reply cmd=... error=0 resid=65536 aux=65536`
— an "error-free" reply whose 64KB aux equals the previous process's
physio buffer (the secret image block), verified by md5.

On the **fix kernel** the same command returns `aux=0`.
