# DF-2977 — VERDICT

**status: reproduced / impact: dos (unauthenticated remote CPU/netisr exhaustion, conditional on accf_http deployment) / confidence: certain**

## What was run

`srv.c` (httpready-filtered listener, port 19000) + `bench.c` on the DF
6.5-DEVELOPMENT guest (stock INVARIANTS kernel), accf_http.ko loaded by root,
client and server both guest-local on 127.0.0.1 (the measurement is of kernel
protocol-thread work, which is identical for a remote attacker).

## Results (kern.cp_time sys-delta, microseconds, 4 connections each)

| request bytes | bulk (control) | byte-at-a-time | per-2x growth |
|---------------|----------------|----------------|---------------|
| 4096          | ~0             | 107,765        | —             |
| 8192          | ~0             | 315,302        | 2.9x          |
| 16384         | ~0             | 1,153,292      | 3.7x          |

Quadratic behavior confirmed (approaching the 4x O(n²) asymptote as fixed
overheads wash out). Wall-clock: 0.396 s vs 0.021 s for 32 KB dribbled vs
bulk. ~0.29 CPU-seconds of system time per single 16 KB connection; the work
runs in tcp_input → sorwakeup → sowakeup (uipc_socket2.c:603-604) →
`soparsehttpvers` on the netisr protocol thread.

## Why it is a bug (path:line)

- sys/net/accf_http/accf_http.c:237-278 — `soparsehttpvers()` restarts the
  scan at `so->so_rcv.ssb_mb` on every upcall; `readmore` (line 279-287)
  re-arms the same full-buffer parser.
- sys/net/accf_http/accf_http.c:225-235 — no parse position/state is kept
  anywhere (the filter gets `void *arg` it never uses to store progress).
- The dispatch is per-arrival: every delivered segment triggers the upcall
  (uipc_socket2.c:603-604).

An unauthenticated remote client choosing "one byte per TCP segment, one
space total, never a newline" converts 16 KB of traffic into ~0.3 CPU-s of
protocol-thread work per connection; N parallel connections pin the netisr
threads that service other sockets hashed to the same CPUs.

## Scope / severity rationale

accf_http is not in GENERIC (no `device accf_*` in sys/config/GENERIC) — an
admin must kldload it and an application must opt in via
setsockopt(SO_ACCEPTFILTER). Within that (intended, documented
http-accelerator) deployment the trigger is fully unauthenticated. Low
severity because of the opt-in precondition; inherited unchanged from the
FreeBSD ancestry of this file.

## Exploit chain

none — pure CPU/resource exhaustion.

## Fix direction (not patch-validated; redesign required)

Keep per-socket parse state (bytes consumed, spaces seen) in a filter-private
struct allocated by `accf_create()` and passed back through `arg`, so each
upcall resumes where the previous one stopped (O(n) total). Interim cheap
mitigation: cap the rescan length (e.g. skip the first `parsed_upto` bytes)
or cap `parse_http_version` scanning at the first 64 KB and fall out to
`soisconnected()`.
