# DF-2695 VERDICT

## Status: REPRODUCED (unprivileged kernel-stack info leak)

`sys_sendfile()` leaks 8 bytes of uninitialized kernel stack to userspace
on every failing `sendfile(2)` call that passes a non-NULL `sbytes` pointer.

## Root cause (line-accurate)

* `sys/kern/uipc_syscalls.c:1594` — `off_t sbytes;` (uninitialized).
* `kern_sendfile()` writes `*sbytes = 0` only at `:1734`, after the early
  error gotos (`done0`) at `:1699-1732` (not VREG, no `v_object`,
  `holdsock` failure, not `SOCK_STREAM`, not connected, `offset < 0`).
* `:1677-1680` — the exit path *unconditionally* runs
  `sbytes += hdtr_size; copyout(&sbytes, uap->sbytes, sizeof(off_t));`
  (copyout error ignored), including on the error paths above.

## Reproduction

* Unprivileged (`maxx`, uid 1001). `leak3.c` shows a **stable** leak: a
  preceding `socket(2)` seeds the stack slot, then
  `sendfile(fd, -1, 0, 0, NULL, &sbytes, 0)` returns `-1/EBADF` with
  `sbytes = 0xfffff80117c88a40` — a DragonFly **kernel virtual address**.
  A first-call variant leaked `0xffffffff809a5db0` (kernel text/data range).
* `run.log` holds the decisive output (root + unprivileged runs).

## Impact

* 8 bytes of kernel stack per call, repeatedly, values include kernel
  pointers → KASLR defeat / kernel-stack fingerprinting on hardened
  systems. Limited to a single stack slot (whichever value the previous
  syscall left at that depth), hence Medium severity (CWE-908 → CWE-200).
* FreeBSD's equivalent code initializes `*sbytes` early and copies it out
  only on success; the unconditional copyout of an uninitialized local is
  DragonFly-specific.

## Fix validation

`fix.diff`: `off_t sbytes = 0;` (one line). Patched kernel (same in-guest
`make nativekernel` build as DF-2694's fix): `poc_sendfile`/`leak3` now
report `0x0000000000000000` on every path (see `fix_run.log`).
