# DF-2854 VERDICT — REPRODUCED (baseline) / fixed by bzero (validated)

## Bottom line
On the stock kernel, an **unprivileged** user (uid 1001, no groups,
securelevel -1) reading `hw.bus.rman` receives, per exported entry,
up to 31 bytes of uninitialized kernel stack from
`struct u_resource.r_devname` (and per-rman `rm_descr`), plus the 4
trailing pad bytes (DF-0092).  On this guest the residue is **a live
kernel virtual address** repeated in every entry:

    r_devname tail: "acpi0" | raw: 61 63 70 69 30 00 ff ff 00 58 ee 17 01 f8 ff ff
                                      a c p i 0  \0  …  [  = 0xfffff80117ee5800  ]
    tail pad bytes 76-79: ff ff ff ff

88 resources + 5 rman descriptors were exported → 99 “UNINITIALIZED”
marks per run; byte-for-byte identical across 3 runs (stable stack
residue; deterministic on this boot).  See run.log / leak_sample.txt.

## Why it leaks (path:line)
- sys/kern/subr_rman.c:653-654 — `struct u_rman urm; struct u_resource
  ures;` are *uninitialized stack locals*.
- :684 `strlcpy(urm.rm_descr, …)` writes only strlen+1 of 32 bytes;
  :707-716 `ksnprintf`/“nomatch”/`'\0'` write only strlen+1 of 32 bytes
  of `r_devname`.
- :690 and :722 `SYSCTL_OUT(req, &x, sizeof(x))` copy the **entire**
  struct (80 bytes) to userland.
- :734 the node is `CTLFLAG_RD` — world-readable (lib/libdevinfo
  walks it as a normal user; our PoC needed no privileges).
- Contrast: the sibling `sysctl_devices` handler deliberately does
  `bzero(&udev, sizeof(udev))` (sys/kern/subr_bus.c:3892) — sysctl_rman
  simply forgot.

## Relation to DF-0092 (not a re-report)
DF-0092 covers the 4 trailing **padding** bytes only and asserts the
named fields are set.  They are not: the partially-initialized string
fields leak up to 31 bytes each — a distinct, ~8x larger surface in the
same function, with kernel-pointer content demonstrated.  DF-0092’s
suggested `struct u_resource ures = {};` would incidentally fix this
too; the root-cause statement (“named fields set”) is what this finding
corrects.

## Impact ceiling
Kernel-stack disclosure to any local user: kernel pointers (KASLR /
heap-layout reconnaissance; useful to weaponize adjacent memory bugs),
possibly other residue depending on prior use of the reader’s kstack.
No write primitive.  Rubric: “local info leak of limited kernel
memory” → Medium, bucket kernleak.

## PoC changes (poc_changes)
- No seed; walker mirrors lib/libdevinfo/devinfo.c:263-345 (OID
  resolution via sysctl(0,3), generation from hw.bus.info).
- First cut had a wrong `struct u_businfo` (used a generation-first
  layout; kernel’s is `{int ub_version; int ub_generation}` per
  sys/sys/bus.h:67) — every request returned EINVAL until fixed.
- Run as unprivileged `maxx` via `vm.sh run_user`.

## Fix validation
- `fix.diff`: `bzero(&urm, sizeof(urm))` / `bzero(&ures, sizeof(ures))`
  before filling (mirrors subr_bus.c:3892).
- Applied in guest together with DF-2853’s guard; single
  `make nativekernel` + installkernel + reboot.
- Patched-kernel expectation (met): all r_devname/rm_descr tails and
  the 4 pad bytes read as zero; `grep -c UNINITIALIZED` → 0.

## Kernel references
- sys/kern/subr_rman.c:653-654, :684, :702-722, :734
- sys/kern/subr_bus.c:3892 (correct bzero pattern)
- lib/libdevinfo/devinfo.c:263-345 (unprivileged walk precedent)
