# DF-2829 — Uninitialized `vm_zone->znalloc` heap data disclosed to unprivileged users via `sysctl vm.zone`

## What

`zinit()` (sys/vm/vm_zone.c:453) allocates `struct vm_zone` with
`kmalloc(..., M_ZONE, M_NOWAIT)` — **no M_ZERO** — and `zinitna()`
(sys/vm/vm_zone.c:347-436) initializes every stats field *except*
`z->znalloc`. That field is only ever *incremented* (vm_zone.c:773,786).
`sysctl_vm_zone()` reads it (vm_zone.c:848) and prints the sum in the
REQUESTS column (vm_zone.c:854-858). `vm.zone` is a stock, world-readable
sysctl (`CTLFLAG_RD`, no privilege gate) — confirmed readable as `nobody`.

Result: 8 bytes of *stale kernel heap memory* (at the fixed offset of
`znalloc` inside a 16640-byte block) cross to unprivileged userspace, as a
decimal long, for every zone created through `zinit()`:
`SWAPMETA` (swap_pager.c:441 — every stock kernel) and the three netbt pools
(bt_proto.c:139-149 on `device bluetooth` kernels). A secondary window: the
zone is `LIST_INSERT_HEAD`'d onto `zlist` (vm_zone.c:359) *before*
`bzero(z->zpcpu,...)` (vm_zone.c:362), so a racing reader can also sum
uninitialized per-CPU slots during the init window.

## Reproduce

Guest (stock `X86_64_GENERIC` INVARIANTS kernel #0, DragonFly 6.5-DEVELOPMENT):

1. `build.sh` — build the KLD harness `df2829.ko` (in-guest, needs /usr/src).
2. `run.sh` as root: `kldload /root/df2829/df2829.ko`
   - the harness grooms the heap: 16 × kmalloc(sizeof(struct vm_zone))
     filled with `0x41`, freed; then `zinit("leakmark_zone", 64, 1, ...)`.
3. Read as an unprivileged user: `sysctl vm.zone | grep leakmark`

## Expected (vulnerable kernel)

```
leakmark_zon 000064, 00000000, 000000, 000000, 4702111234474983745
```

`4702111234474983745` = `0x4141414141414141` — exactly the groomed marker,
proving the uninitialized heap field reached userspace. On the *patched*
kernel the same run prints `REQUESTS 00000000`.

## Files

- `df2829_harness.c` — KLD groom + zone source
- `build.sh` / `run.sh`
- `build.log` / `run.log` — decisive run (root + `nobody` reads)
- `fix_validation.log` — patched-kernel rerun (marker gone)
- `fix.diff` — git-apply-able fix (znalloc init + M_ZERO + bzero reorder)
- `manifest.json`, `verdict.json`
