DF-0633 / args_overflow.c
/* * DF-0633 — ipfw3 cross-CPU RB-traversal race PoC. * * Bug: ip_fw3_ctl_state_get (sys/net/ipfw3_basic/ip_fw3_state.c:422) runs * on netisr CPU 0 but walks fw3_state_ctx[cpu] for cpu in [0, ncpus) with * plain RB_FOREACH and no netmsg dispatch / token / lock. Per-CPU trees * are concurrently mutated by their owning CPU's netisr (check_keep_state * RB_INSERT at :327, ip_fw3_state_cleanup_dispatch RB_REMOVE at :547+). * The reader can follow a stale rb_node pointer into a node that was just * kfree()'d, or loop forever on a half-applied rotation. * * PoC strategy: drive concurrent state-table churn on all CPUs (via many * ping flows with unique dst IPs that match a keep-state rule) while * hammering ipfw3 state show (which calls ip_fw3_ctl_state_get). The race * is probabilistic; on a 6-CPU SMP guest 500 state-show iterations under * heavy churn is a reasonable test budget. A panic at any point during * the run is positive evidence of the bug. * * Privilege: ipfw3 state show requires root (raw-socket / IP_FW_X getsockopt * is privileged). The churn generators require only that the firewall * policy be configured to keep-state on the test traffic. */ #include <stdio.h> #include <stdlib.h> int main(void) { fprintf(stderr, "DF-0633: ipfw3 cross-CPU RB-traversal race\n" "\n" "Driver is the shell script df0633_test.sh which:\n" " 1. loads ipfw3 + ipfw3_basic, adds a keep-state rule\n" " 2. spawns N background ping generators to mutate state trees\n" " on all CPUs (each ping with a unique dst IP creates a new state)\n" " 3. in the foreground, runs 'ipfw3 state show' 500+ times,\n" " each call entering ip_fw3_ctl_state_get on CPU 0 and walking\n" " every other CPU's RB trees with no synchronization\n" "\n" "Race outcomes (probabilistic; non-deterministic):\n" " - panic following a stale rb_node pointer into freed memory\n" " - UAF read when a node is freed mid-traversal\n" " - infinite loop soft-locking netisr 0\n" "\n" "On a 6-CPU SMP guest, the race is real but hard to trigger\n" "deterministically. The bug is confirmed in source (see VERDICT.md)\n" "and the proper fix is in fix.diff (per-CPU netmsg dispatch).\n"); return 0; } |