# DF-2836 VERDICT

**Status: reproduced** (unprivileged, 3/3 runs on the stock INVARIANTS kernel)
**Impact: dos** — accepted connections born half-shut; availability/correctness
defect, no memory unsafety.

## Root cause (path:line)

`sys/kern/uipc_socket2.c:383` — `sonewconn_faddr()`:

```c
so->so_state = head->so_state | SS_NOFDREF | SS_ASSERTINPROG;
```

The child socket inherits the listener's *entire* `so_state` word. A listener
that has been `shutdown(SHUT_WR)` carries `SS_CANTSENDMORE`
(`soshutdown` → `so_pru_shutdown` → `socantsendmore`, uipc_socket.c), so every
child born afterwards (AF_UNIX `unp_connect` → `sonewconn_faddr`,
uipc_usrreq.c:1215) is born with `SS_CANTSENDMORE`. `accept()` hands the user
a socket whose first `send(2)` returns `EPIPE` while the connection is fully
live (data flows in the other direction — proven by `recv()` returning the
peer's bytes in the same run).

Upstream FreeBSD inherits only the NBIO bit in its `sonewconn` (their fix for
this same defect); DragonFly keeps NBIO in `fp->f_flag`, so nothing needs to
be inherited at all.

## Reproduction

Unprivileged `./stateinherit` (see run.log / run.2.log):

```
unix: shutdown(listener, SHUT_WR) = 0
unix: connect ok, accept = 7
unix: client  send  = 4
unix: accepted recv = 4 (No such file or directory)   <- connection is LIVE
unix: accepted send = -1 errno=32 [Broken pipe]  <-- want 4; EPIPE(32) = BUG
```

First run before SIGPIPE was trapped died of SIGPIPE — itself proof that the
kernel treated the freshly accepted socket as write-dead.

TCP variant: `shutdown(SHUT_WR)` on a TCP listener makes tcp refuse new
connections outright ("Connection refused"), so the AF_UNIX listen path is
the demonstrable path; the defective line is family-independent.

## Fix validation

`fix.diff` (inherit only `SS_NOFDREF | SS_ASSERTINPROG`) applied to the
guest's `/usr/src` copy together with the DF-2838 padding fix, kernel rebuilt
(`make nativekernel KERNCONF=X86_64_GENERIC`) and the exact same PoC re-run:

* baseline (stock): `accepted send = -1 errno=32` (3/3)
* patched: `accepted send = 4`, full bidirectional data flow (see
  `fix_validation.log`)

Behavior change is gone ⇒ fix validated.

## Threat

Unprivileged local (AF_UNIX) or any remote peer (TCP configs where the
listener keeps accepting after shutdown): connections accepted during a
graceful-listener-shutdown window (the canonical daemon-restart pattern) are
silently dead-on-arrival. No privilege boundary is crossed.
