# DF-0993 — fill_dbregs() uninitialized dr[8]-dr[15] leak

## Verdict
**REPRODUCED + FIX VALIDATED.** Uninitialized kernel stack residue is leaked
through `/proc/<pid>/dbregs` (and `PT_GETDBREGS`). The single-line fix
(`memset`/loop-zero `dr[8..15]` in `fill_dbregs`) closes the leak; verified
by building and booting a single-fix kernel.

## Mechanism (cited)

`struct dbreg` is `unsigned long dr[16]` = 128 bytes
(`sys/cpu/x86_64/include/reg.h:89-96`). Architecture defines only `dr[0]`–`dr[7]`;
`dr[8]`–`dr[15]` are reserved.

`fill_dbregs()` at `sys/platform/pc64/x86_64/machdep.c:3104-3130` populates
**only** `dr[0]`–`dr[7]` (64 bytes). The reserved `dr[8]`–`dr[15]` (64 bytes)
are never written.

`procfs_dodbregs()` at `sys/vfs/procfs/procfs_dbregs.c:51-77` declares
`struct dbreg r;` at line 57 **without zero-initialization**, then calls
`procfs_read_dbregs(lp, &r)` → `fill_dbregs(lp, &r)` (only 64 bytes written),
and finally `uiomove_frombuf(&r, sizeof(r), uio)` at line 67 copies the full
128-byte struct back to userspace — leaking the 64 uninitialized bytes from
the kernel stack.

`p_trespass(curp->p_ucred, p->p_ucred)` returns 0 for `self`
(`procfs_dbregs.c:62`), so the leak is reachable by any unprivileged local
user via `/proc/self/dbregs`. The `ptrace(PT_GETDBREGS)` path goes through
the same `procfs_dodbregs` (`sys/kern/sys_process.c:537-559`).

Same bug class as DF-0938 (`fpregs`); DF-0993 corrects the DF-0938 note that
"dbregs is fully populated" — it is **not**.

## Exploit chain / Impact
- **Class**: info leak (uninitialized kernel memory to userspace).
- **No escalation chain** — this is a pure read primitive (no write, no
  corruption). The realistic impact ceiling is **KASLR-assist / pointer
  leak**: the leaked bytes routinely contain canonical kernel virtual
  addresses (`0xfffff8XX_XXXXXXXX`) and other stack residue from the
  syscall return path. This is exactly the kind of residue an attacker
  uses to defeat KASLR or to refine slab-grooming offsets for a separate
  memory-corruption primitive.
- **CVSS** as filed: `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N` (Medium).

## PoC
- `dbregs_leak.c` — opens `/proc/self/dbregs`, reads 128 bytes, dumps all 16
  `dr[]` values. Mode 0 = single verbose dump; mode 1 = fork-and-read across
  fresh kernel threads to demonstrate variance.
- `build.sh` — `cc -O -o dbregs_leak dbregs_leak.c`
- `run.sh` — runs both modes.

### Observed output on the unpatched 6.5-DEVELOPMENT #0 baseline
```
dr[ 8] = 0xfffff800905fc780   <-- UNINITIALIZED (should be 0)
dr[ 9] = 0x0000000000000400   <-- UNINITIALIZED (should be 0)
dr[10] = 0x0000000000000000   <-- UNINITIALIZED (should be 0)
dr[11] = 0x00000000807093d0   <-- UNINITIALIZED (should be 0)
dr[12] = 0x000005c000000000   <-- UNINITIALIZED (should be 0)
dr[13] = 0xfffff8008d9fade0   <-- UNINITIALIZED (should be 0)
dr[14] = 0xfffff80116aa90a8   <-- UNINITIALIZED (should be 0)
dr[15] = 0xfffff80116aa8c80   <-- UNINITIALIZED (should be 0)
[verdict] dr[8..15] residue_or=0xfffffdc19ffffff8 LEAK
```
- Bytes vary across program executions (see `leak_sample.txt`) — confirming
  live uninitialized stack residue rather than a fixed sentinel.
- The values are canonical kernel pointers in the `0xfffff8XX_XXXXXXXX`
  range — direct KASLR-bypass / kernel-base material.

## Fix
`fix.diff` — adds a loop in `fill_dbregs()` that zeros `dr[8..15]` before
the rest of the function runs. Minimal and targeted at the root cause.

The single-fix kernel (X86_64_GENERIC #1, built from the patched source) was
booted and the PoC re-run three times: `dr[8..15]` are all-zero on every run
(`residue_or=0x0 clean`). See `fix_run.log` and `fix_build.log`.

## Files in this evidence pack
- `dbregs_leak.c` / `dbregs_leak` — PoC source + binary
- `build.sh`, `run.sh` — exact reproduce commands
- `build.log` — compiler output (final successful build)
- `run.log` — decisive run on unpatched kernel
- `leak_sample.txt` — 3 successive runs on the baseline showing variance
- `baseline_run.log` — fresh `vm.sh reset with-src` baseline run (the "before")
- `fix.diff` — minimal fix (zero `dr[8..15]` in `fill_dbregs`)
- `fix_build.log` — full `nativekernel` build output of the patched kernel
- `fix_run.log` — 3 runs on the patched kernel (#1) — all clean
- `env.txt` — guest environment
- `manifest.json` — artifact catalog
