# DF-3204 — krpc_call leaks the reply mbuf chain on the RPC_PROGMISMATCH exit

**File:** `sys/vfs/nfs/krpc_subr.c:391-396` (leaking exit), `:437-441`
(the `out:` path that never frees `m`)
**Severity:** Low · **CWE-401** · verified in VERIFY mode with the
verbatim-interposition kernel-compiled rig (`dfrig13_krpc.c`, sha256-gated
`#include` of the production `krpc_subr.c`; real UDP stack, real mbufs,
userland attacker `attacker.c` mode `pmis`).

## What was reproduced (baseline kernel #1)

The attacker answers each request with an in-bounds 24-byte accepted reply
whose `rp_status` = 2 (`RPC_PROGMISMATCH`, bytes 20..23 on the wire — no OOB
involved). The verbatim code at :393-395 executes
`error = EBADRPC; goto out;` with `m` still owning the soreceive-d reply
chain, and the `out:` path frees only `mhead` and `from` and closes the
socket — `m` is never freed.

```
mbufs before: 7/146632 mbufs in use
mbufs after:  57/146632 mbufs in use     # 50 calls -> exactly +50 leaked
```
(`run.log` T3: 50/50 calls returned EBADRPC.)

**Control** (T33, honest replies transferred to the caller and freed):
```
mbufs before control: 57   ->   after: 57     # +0
```

**DF-3203 coupling** (the same leak taken via the *uninitialized* read):
planting `0x00000002` at mbuf offset 20..23 with the userland primer and
sending a 16-byte short reply → 3/3 calls returned EBADRPC with exactly
+3 leaked mbufs (`run.couple.log`, detailed in the DF-3203 pack) — the leak
exit taken on a stale value, and incidentally the same path a v2-only
mountd drives during the normal md_mount v3→v1 fallback (nfs_mountrpc.c
:140-163: v3 EBADRPC → v1 retry, one leaked chain per boot RPC).

## Fix validation (kernel #2)

With `fix.diff` (`m_freem(m); m = NULL;` before the `goto out`): 50/50
calls still return EBADRPC (PROGMISMATCH semantics unchanged) and
```
mbufs before: 8  ->  after: 8     # +0 — leak gone
```
honest control stays flat (`run.fixed.log`).

## Reproduce (on the DragonFly guest)

```
sh build.sh                     # gate + build + install; reboot
sh run.sh                       # T3 leak (+50) + T33 control (+0)
# fix validation:
sh build.sh af834f6e30225b1af68cc83cbcdaf25e29e0e39ca6deaec6f3c13663a661b886 ; reboot
sh run_fixed.sh                 # (in DF-3205 pack) T3 +0
```

## Files in this folder

| file | purpose |
|---|---|
| `dfrig13_krpc.c` / `attacker.c` | harness + userland attacker (mode pmis) |
| `build.sh` / `run.sh` | exact commands |
| `run.log` / `pmis.log` / `good.log` | baseline decisive run (netstat brackets, attacker view) |
| `run.couple.log` | DF-3203-stale-value coupling (+3) |
| `run.fixed.log` / `fx_pmis.log` / `fx_good.log` | fixed-kernel A/B |
| `build_summary.log` | build gate excerpts (full logs in DF-3205 pack) |
| `fix.diff` / `fix_all.diff` | validated fix (single / combined) |
| `env.txt`, `VERDICT.md`, `manifest.json`, `verdict.json` | context + verdicts |
