# DF-2672 — vm_object reference leak on fork() of wired (mlock'd) VM entries

## What

`vm_map_copy_entry()` (sys/vm/vm_map.c:3600) handles the fork of a **wired**
(`src_entry->wired_count != 0`) map entry by scrapping the cloned child
entry's object and copying the pages into a fresh one.  Its comment claims
"its ref-count has not yet been adjusted so we can just NULL out the field",
but that stopped being true with the `vm_map_backing` rework:
`vmspace_fork_normal_entry()` (sys/vm/vm_map.c:3882) calls
`vm_map_backing_replicated(new_map, new_entry, 0)` **before**
`vm_map_copy_entry()` (sys/vm/vm_map.c:3889), and with `flags == 0` that
function takes a reference on the base object
(`vm_object_reference_quick()`, sys/vm/vm_map.c:3510-3513).

The wired path detaches and NULLs `dst_entry->ba.map_object`
(sys/vm/vm_map.c:3627-3634) without dropping that reference →
**one vm_object reference leaks per fork() of a wired entry**.

## Impact

Unprivileged local user (mlock works within RLIMIT_MEMLOCK, default =
free_memory/3, no privilege needed — sys/vm/vm_mmap.c:1020-1031,
sys/kern/kern_plimit.c:131-132):

* leaked vm_objects are never freed (`vm_object_deallocate` never sees 0);
* their dirty anonymous pages, once paged out under memory pressure, keep
  their **swap space allocated forever** (`swap_pager_freespace` only runs
  at object termination);
* permanent kernel-memory + swap exhaustion → system-wide DoS that survives
  the death of the offending processes.  No RLIMIT bounds the accumulated
  leak across processes.

## Reproduce (on the audit QEMU guest)

```
./build.sh   # cc -O2 -o /tmp/leak_fork leak_fork.c    (+ hog.c)
./run.sh     # control vs leak phases + memory pressure
```

Success criterion: `vmstat -m` "vm_object" Count grows by ~1 per leak
iteration and never returns; control run returns to baseline.  After
pressure, `swapinfo` shows hundreds of MB permanently consumed with no
processes owning anonymous memory.

## Fix

`fix.diff` — call `vm_object_deallocate()` before NULLing the field
(mirrors `vm_map_entry_dispose()`, sys/vm/vm_map.c:1132-1135).
Validated by kernel rebuild + PoC re-run (see VERDICT.md).
