DragonFlyBSD Kernel Audit
DF-0391 / fix_run.log
← back to finding ↓ download raw
=== BASELINE kernel kern.version ===
DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
=== Setup ===
kldload pf
echo "scrub in on lo0 all fragment crop" > /etc/pf-0391.conf (+ pass rules)
pfctl -f /etc/pf-0391.conf ; pfctl -e

=== Run as root (sender: raw IP frags to 127.0.0.1) ===
Two overlapping fragments per round (off=0/MF, off=8/no-MF), each round with new ip_id,
with concurrent mbuf-pressure children. See df_0391_fragcache.c.

=== pfctl -s info (after ~6s of running) ===
Status: Enabled for 0 days 00:00:41           Debug: Urgent
Counters
  match                               1406
  fragment                               1     <-- pf detected an overlapping fragment
  normalize                           1066     <-- pf_normalize_ip + fragcache path entered
  memory                                 0     <-- no m_dup NULL failure

=== dmesg during run ===
Warning: objcache(mbuf pkthdr+cl) exhausted on cpu1!    <-- pressure WAS applied
Warning: objcache(mbuf pkthdr+cl) exhausted on cpu2!
Warning: objcache(mbuf pkthdr+cl) exhausted on cpu3!
Warning: objcache(mbuf pkthdr+cl) exhausted on cpu4!
Warning: objcache(mbuf pkthdr+cl) exhausted on cpu5!

=== Observation ===
The fragcache overlap path IS reached (normalize 1066, fragment 1).
The mbuf pool IS exhausted (objcache warnings on all CPUs).
But m_dup(M_NOWAIT) did NOT return NULL — DragonFly's objcache transparently
refills from the master allocator before failing, so the NULL-deref condition
was not hit. No panic occurred. The bug is CERTAIN by code inspection
(sys/net/pf/pf_norm.c:663-664 dereferences *m0 before the NULL check at :665)
but the live trigger is non-deterministic on this guest.

=== PATCHED kernel kern.version ===
DragonFly 6.5-DEVELOPMENT #1: Sat Jul 18 05:51:46 UTC 2026
(both kernel and /boot/kernel/pf.ko rebuilt & installed via make installkernel)
=== Run identical PoC on patched kernel ===
Path still reached (normalize counter incremented).
No panic observed (consistent with baseline — m_dup did not return NULL).
The fix reorders the NULL check before the m_adj deref; the code path is
closed by inspection. Since the panic was non-deterministic to begin with,
this is a not_testable fix validation (diff applies, compiles, module loads,
path still reachable, no panic on baseline or patched under our pressure).