accf_http soparsehttpvers() restarts its scan at ssb_mb on every data arrival with no retained parse state β O(n^2) per connection, all on the netisr protocol thread; unauthenticated remote CPU/netisr exhaustion for any httpready-configured listener
| Field | Value |
|---|---|
| ID | DF-2977 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L |
| CWE | CWE-405 |
| File | sys/net/accf_http/accf_http.c |
| Lines | 237-287 (found in uipc_accf.c pass-2 consumer sweep) |
| Area | net |
| Confidence | certain |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:net? (see bucket field) |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
The httpready filter's version parser walks the ENTIRE accumulated receive buffer from byte 0 on every upcall and, when the request is still incomplete, re-arms itself for the next arrival without remembering how far it already scanned β the accf_create/arg state mechanism that would hold the parse position is never used. A remote unauthenticated client sending 'GET /aaaa...' with exactly one space, no newline, one byte per TCP segment keeps the filter in readmore forever: b buffered bytes cost Ξ£i byte-visits plus b upcalls, quadratic, all executed synchronously in tcp_inputβsowakeup on the protocol thread that also serves other sockets hashed to that CPU. Measured on the guest: 4096/8192/16384 dribbled bytes cost 107765/315302/1153292 Β΅s of kernel system time per 4 connections (2.9Γβ3.7Γ per doubling β O(nΒ²)), ~18,000 CPU-Β΅s per attacker byte vs ~0 for the same bytes sent bulk. Low severity because accf_http is an opt-in kld absent from GENERIC. Fix: persist per-socket parse state (implement accf_create/destroy returning a scan-position struct); interim cap the rescan or fall out to soisconnected() after 64 KB.
Timeline
- 2026-09-02 Discovered during pass-2 audit of uipc_accf.c (GLM 5.3); O(nΒ²) measured on guest.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2977 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| bench.c | β | 2.7 KB | view raw | |
| srv.c | β | 1.5 KB | view raw | |
| build.sh | β | 71 B | view raw | |
| run.sh | β | 537 B | view raw | |
| build.log | β | 150 B | view raw | |
| run.log | β | 698 B | view raw | |
| run.2.log | β | 785 B | view raw | |
| env.txt | β | 224 B | view raw | |
| VERDICT.md | β | 2.8 KB | β raw |
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 atso->so_rcv.ssb_mbon 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 *argit 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().
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
['run.log: byte-at-a-time 8192x4conns = 387259us sys vs bulk = 0us (same bytes)', 'run.2.log: 4096->8192->16384 = 107765->315302->1153292 us (quadratic sweep)', 'VERDICT.md: soparsehttpvers restarts at ssb_mb every upcall, readmore re-arms full scan']
PoC changes
removed duplicate struct accept_filter_arg (guest
Verified recommended fix
Persist per-socket parse state (via accf_create-provided arg) so each upcall resumes scanning where the last stopped, making the total work O(n).
Verdict
Quadratic re-parse reproduced: an httpready-filtered socket fed 4096/8192/16384 bytes one TCP segment at a time (one space, no newline) consumed 107765/315302/1153292 us of kernel system time on the netisr protocol thread (bulk control: ~0), growth 2.9x-3.7x per doubling of request size -> O(n^2). ~0.29 CPU-s per 16KB connection, ~18000 CPU-us per attacker byte; unauthenticated remote CPU/netisr exhaustion for any server opting into accf_http.
No comments yet.