# DF-2838 VERDICT

**Status: reproduced** (unprivileged; nonzero kernel-stack bytes in ≥2/3 runs,
contents matching kernel-pointer patterns)
**Impact: leak** — limited (8 bytes per pcb record) uninitialized kernel stack
disclosed to unprivileged users.

## Root cause (path:line)

* `sys/kern/uipc_socket2.c:188-198` — `ssbtoxsockbuf()` fills the 7 named
  fields of `struct xsockbuf` (46 content bytes) but never the 2 tail-padding
  bytes (struct size 48).
* `sys/kern/uipc_socket2.c:827-848` — `sotoxsocket()` likewise leaves
  `struct xsocket`'s 4 tail-padding bytes (164 → 168) uninitialized.
* Sink: `sys/netinet/tcp_subr.c` `tcp_pcblist_sysctl()` (~1265) uses a stack
  `struct xtcpcb xt;` that is never zeroed and `SYSCTL_OUT`s the full record
  to any reader of `net.inet.tcp.pcblist` (world-readable).

Per record: 2 (so_rcv pad) + 2 (so_snd pad) + 4 (xsocket tail pad) = 8 stale
kernel-stack bytes. (`in_pcb.c:2467` pre-zeroes its buffer; the AF_UNIX
variant of this class was filed as DF-2558.)

## Reproduction

Unprivileged `./pcbleak` — dumps exactly the three pad regions per record,
3 runs with connection churn in between (run.log / run.2.log / run.3.log):

```
rec#0 pads: rcv=ffff snd=0000 tail=fffff801     (runs 1-2, all records)
rec#0 pads: rcv=ffff snd=0000 tail=00000000     (run 3)
```

* `so_rcv` pad = `0xffff` in every record of every run — deterministic
  non-zero stack residue.
* `xsocket` tail pad = `0xfffff801` — the upper half of a kernel-range
  pointer (`0xfffff801xxxxxxxx`), the same address class seen in the
  verified DF-2702 leak. Value varies with stack history (zeroed in run 3),
  confirming it is uninitialized memory and not a constant.

Leaked bytes match kernel-memory pattern across ≥2 of 3 runs ⇒ `leak`,
`reproduced` per the honest-status table.

## Fix validation

`fix.diff` (bzero the exported structs in `ssbtoxsockbuf`/`sotoxsocket`)
applied in-guest together with the DF-2836 fix, kernel rebuilt, PoC re-run:
**all pad bytes zero in all records, all runs** (`fix_validation.log`).
Baseline vs patched differ exactly on the leak ⇒ fix validated.

## Threat

Unprivileged local user reads 8 bytes/record of kernel stack residue; when
the residue contains pointer halves it is KASLR-relevant information. The
disclosure is structurally deterministic (the pads are never written), so an
attacker can retry under differing stack histories to harvest more samples.
