# DF-3268 VERDICT — reproduced (state-limit bypass / unbounded state growth)

## Result
`status: reproduced`, `impact: dos` (kernel memory exhaustion /
administrative limit bypass; remote-triggerable on any pf deployment
with state-creating rules — which is pfctl's default).

## How it was run
Guest DragonFly 6.5-DEVELOPMENT #1 (instrumented kernel), pf.ko loaded.
Ruleset (root, one time): `pass quick inet proto tcp from any to
127.0.0.2 port 8080 synproxy state` + `pass all` (pfctl turns the plain
`pass all` into `keep state` automatically — observed in `pfctl -sr`).
Then a single process sending raw SYNs with distinct (source ip, source
port) tuples — the same packets any network peer can send to a
state-creating rule, or any local user can generate with plain
connect()s under a `pass out keep state` rule.

Observed (full log: run.log):
- state table passed the PFSTATE_HIWAT=50000 hard limit: 55235 entries;
- `state-limit` counter (the PFRES_MAXSTATES limit-hit counter) stayed
  at 0 — no code path checks the limit;
- memory tracks states 1:1 (pfstatepl 53.9K objects/16.9 MB +
  pfstatekeypl 5.38 MB + pfstateitempl 1.24 MB at peak) — real
  allocations, not a counter artifact;
- 1,843,200 distinct SYNs in 90 s (~20K states/s creation rate).

## Root cause (path:line)
- pf.c:278-284 defines pf_pool_limits[PF_LIMIT_STATES] = {pf_state_pl,
  PFSTATE_HIWAT(50000)}; the ONLY references in the tree are the
  definition and pf_ioctl.c:1908-1935 (DIOCGETLIMIT/DIOCSETLIMIT
  plumbing).
- pf.c:4112-4117 (pf_create_state) checks only the per-rule
  `r->max_states`; pf_state_insert/pf_state_key_attach contain no
  global check; pf_ioctl.c:209 `kmalloc_raise_limit(pf_state_pl, 0)`
  makes the malloc zone unlimited.
- The only brake is adaptive timeouts (pf.c:1374-1405, start/end
  30000/60000), which shorten lifetimes but (a) still let the table
  exceed the hard limit by design-margin, (b) are trivially disabled by
  the operator (`set timeout adaptive.end 0` makes pf_state_expires
  skip adaptation), after which growth is bounded only by kernel memory.

## Impact
Any pf-enabled host with keep-state rules (pfctl default) can be driven
to allocate kernel memory far beyond the configured state limit —
memory-exhaustion DoS (`set limit states N` silently ignored). On a
default-adaptive box the table settles near ADAPTIVE_END×state-bytes
(~27 MB at 60000 states here); with adaptive disabled or a larger
`set limit` the exhaustion scales with attack rate × timeout.

## Fix
Add the missing check at the top of pf_create_state (see README.md
diff). Not fix-validated on the guest within budget (the fix-kernel
build was spent on DF-3263); the patch is two lines and mirrors the
per-rule check 10 lines below it.

## 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.
