# DF-3372 VERDICT — sockaddr read-before-validate in TCP bind/connect paths

## Reproduced?

**No observable manifestation — `not_reproduced` (defect itself certain by
code path).**

## What was verified

1. **The read is real (by construction).** `getsockaddr`
   (sys/kern/uipc_syscalls.c:1523) kmallocs exactly `namelen` bytes
   (≥2, ≤255) and copies only those; `tcp_usr_bind`
   (sys/netinet/tcp_usrreq.c:316-321) / `tcp_usr_connect` (:597-602) /
   `tcp_usr_preconnect` (:965-968) then read `sin_family` and
   `sin_addr.s_addr` (offsets 4..7) before `in_pcbbind`'s `sa_len == 16`
   gate (sys/netinet/in_pcb.c:648). The v6 twins
   (`tcp6_usr_bind` :406-411, `tcp6_usr_connect` :640-656) read
   `sin6_addr` (offsets 8..23) — for `namelen` 8 this is 16 bytes fully
   past the 8-byte slab chunk — and additionally pass the short buffer to
   `prison_remote_ip` (sys/kern/kern_jail.c:469-472), which reads address
   fields with no length check of its own.

2. **The multicast decision consumes `sin_addr` regardless of sa_len**
   (guest-verified, deterministic): bind with a **5-byte** sockaddr
   (`sa_len=5`, copied byte 4 = 224) → `EAFNOSUPPORT`; byte 4 = 8 →
   `EINVAL` (see probe2.log / probe_matrix.log). This proves the handler
   bases its decision on a `sockaddr_in` whose declared length (5) is
   smaller than the fields it reads (8 bytes of sin_addr); for
   `namelen` ≤ 4 the decision bytes are entirely uncopied.

3. **The recycled-byte oracle does not flip on the stock allocator**
   (the honest negative): ~600k groomed attempts (8-byte and 16-byte
   M_SONAME grooms via UDP bind and sendto, 2..256 reps, single- and
   48-process fleets, 200k-iteration hammers — probe.log, probe2.log,
   probe3.log) produced zero EAFNOSOURCE flips for `namelen` ≤ 4.
   Root cause of the resilience: DF's slab allocator puts cross-CPU
   frees on the owning CPU's `z_RChunks` remote list
   (sys/kern/kern_slaballoc.c:1491-1547) which user-thread allocations
   do not immediately reuse, and the v6 cross-object byte the multicast
   test samples is the neighbouring chunk's `sa_len` byte (structurally
   8, never 0xff). Affinity pinning (`usched_set`) is privileged, so the
   owner-CPU LIFO reuse could not be forced unprivileged.

## Impact ceiling

1-bit error-code oracle (EAFNOSUPPORT vs EINVAL) on kernel heap contents
beyond the user-copied length, per bind/connect attempt — but not
reliably groomable on the stock kernel (see 3). No data leaves the
kernel; no write primitive. This is the DF-3357 family with a much lower
ceiling because TCP never *uses* the OOB address (UDP did).

## Classification

status=not_reproduced, reproduced=0, impact=none, confidence=certain
(that the OOB read occurs), severity Low, CWE-125.

## Fix

Validate `sa_len` (and family) before any field read at the five sites,
e.g. `tcp_usr_bind`:

```c
if (nam->sa_len < sizeof(struct sockaddr_in)) {
        error = EINVAL;
        goto out;
}
```
mirrored for connect/preconnect (sizeof(sockaddr_in)) and the v6 twins
(sizeof(sockaddr_in6)), plus a length guard inside `prison_remote_ip`
callers or in `prison_remote_ip` itself.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
