#!/bin/sh
# DF-0604 — Live cross-CPU race trigger (corrected approach)
#
# The original finding claimed concurrent SIOCAIFADDR calls race on pfi_buffer.
# That's WRONG: SIOCAIFADDR dispatches ALL work to netisr0 (in.c:248), so
# all ifaddr_events serialize on netisr0 — no cross-CPU overlap.
#
# The REAL race window is between:
#   (A) pfioctl path: DIOCADDRULE -> pfi_dynaddr_setup -> pfi_kif_update
#       -> pfi_dynaddr_update -> pfi_table_update — runs on CALLER'S CPU
#       (pfioctl does NOT dispatch to netisr0)
#   (B) ifaddr_event path: SIOCAIFADDR (dispatched to netisr0) ->
#       pfi_ifaddr_event -> pfi_kif_update -> pfi_table_update — runs on NETISR0
#
# These two paths CAN overlap: CPU X is inside pfi_table_update (blocked on
# netisr_domsg to fill the buffer), while netisr0 is running its own
# pfi_table_update for the ifaddr_event. Both modify the shared globals.
#
# This script runs both churners in parallel to trigger the race.
# Must be run as root with pf loaded.

PFCONF=/tmp/pf_0604.conf
PFDEV=/dev/pf

cat > "$PFCONF" << 'PFEOF'
pass quick on vtnet0 inet from (vtnet0) to any
pass quick on vtnet0 inet6 from (vtnet0) to any
block in quick from (vtnet0:network) to any
PFEOF

echo "DF-0604 corrected race trigger: pfctl churn + ifaddr churn"
echo "  (A) pfctl -f loop on caller CPU (triggers pfi_table_update on caller CPU)"
echo "  (B) ifconfig alias/-alias loop (triggers pfi_table_update on netisr0)"
echo ""

DURATION=${1:-30}

# (A) pfctl rule churn: flush + reload rules with dynamic interface expansion
# Each reload calls pfi_dynaddr_setup -> pfi_table_update on the calling CPU
( while true; do
    pfctl -d >/dev/null 2>&1
    pfctl -F all >/dev/null 2>&1
    pfctl -f "$PFCONF" >/dev/null 2>&1
    pfctl -e >/dev/null 2>&1
  done
) &
PFCTL_PID=$!
echo "pfctl churn pid=$PFCTL_PID"

# (B) ifaddr churn: SIOCAIFADDR alias/-alias on vtnet0
# Dispatched to netisr0, triggers ifaddr_event -> pfi_table_update on netisr0
(
  s=$(socket -dgram -inet 2>/dev/null) || true
  COUNT=0
  while true; do
    ifconfig vtnet0 alias 10.0.99.1/32 2>/dev/null
    ifconfig vtnet0 -alias 10.0.99.1 2>/dev/null
    COUNT=$((COUNT + 1))
  done
) &
IFADDR_PID=$!
echo "ifaddr churn pid=$IFADDR_PID"

echo "running for ${DURATION}s..."
sleep "$DURATION"

kill $PFCTL_PID $IFADDR_PID 2>/dev/null
wait $PFCTL_PID $IFADDR_PID 2>/dev/null

# Clean up pf state
pfctl -d >/dev/null 2>&1
pfctl -F all >/dev/null 2>&1

echo "race trigger complete"
