# DF-0598 — PoC: smb_sm_lookupint VC refcount leak

Privileged local DoS (memory-exhaustion + kernel-thread hang) in the
DragonFlyBSD in-kernel SMB client.  Each failing `SMBIOC_LOOKUP`-style
operation leaks one VC reference via the stale post-loop `vcp` at
`sys/netproto/smb/smb_conn.c:175-178`.  Repeat to bump `co_usecount`
unboundedly on a victim VC (the VC can then never be freed, and a closer
racing with teardown hangs forever in `smb_co_gone` at `smb_conn.c:263-265`).

The vulnerable code is `optional netsmb` and is **not** compiled into the
audited `X86_64_GENERIC` kernel; it ships as the loadable `smbfs.ko` KLD
(which builds & loads cleanly on this guest, creating `/dev/nsmb` mode 0700
root).  See `VERDICT.md` for the full reachability analysis.  This PoC is a
**code-level proof** (mirrors the DF-0265 latent-config precedent) backed by
**disassembly of the actual shipped KLD** proving the compiler retained the
stale-write leak.

## Files

- `leak.c` — userspace harness replicating `smb_sm_lookupint` line-for-line
  (vulnerable + fixed variants) with a 3-VC driver.
- `fix.diff` — `git apply`-able two-hunk fix (validated: KLD builds + loads,
  disasm confirms the leak is closed).
- `VERDICT.md` — full narrative + Phase 8 fix-validation results.
- `manifest.json` — machine-readable artifact catalog.
- Logs: `build.log`, `run.log` (N=10), `run.1000.log` (N=1000),
  `fix_build.log`, `fix_build_unpatched.log`, `unpatched.dis`,
  `patched.dis`, `leak_sample.txt`, `env.txt`.

## Build & run

```
./build.sh
./run.sh           # default 10 failing lookups
./run.sh 1000      # stress: linear leak at scale
```

## Expected output

```
=== VULNERABLE smb_sm_lookupint ===
  call #0: rc=1 (lookup FAILED), but *vcpp=alice@a (NOT NULL!)
  after 10 failed lookups:
    usecount[alice@a] = 11  (baseline 1, delta +10)   <-- 10 refs LEAKED
    ...
=== FIXED smb_sm_lookupint (fix.diff applied) ===
  after 10 failed lookups:
    TOTAL leaked refs across all VCs = 0               <-- leak CLOSED
```

At N=1000 the vulnerable variant leaks exactly +1000 refs (linear); the fixed
variant leaks 0 at any N.  See `VERDICT.md` §4 for the compiled-KLD
disassembly proof that the unpatched `smbfs.ko` actually contains the leak
(`je 1fa0` → `callq smb_co_ref` on stale `%r14`) while the patched KLD does
not (`je 1fa6` → epilogue).

## In-kernel reproduction (requires an SMB server, not available on this guest)

The harness proves the C-level logic.  To reproduce end-to-end in the kernel:
stand up an SMB server reachable from the guest, load `smbfs.ko`, mount the
share once via `mount_smbfs` (to populate the vclist), then loop
`ioctl(fd, SMBIOC_LOOKUP, ...)` with a non-matching username and watch the
victim VC's `co_usecount` climb via `vmstat -m` / a `net.smb.treedump` sysctl.
