DF-0572 / fix.diff
diff --git a/sys/net/ipfw3_nat/ip_fw3_nat.c b/sys/net/ipfw3_nat/ip_fw3_nat.c --- a/sys/net/ipfw3_nat/ip_fw3_nat.c +++ b/sys/net/ipfw3_nat/ip_fw3_nat.c @@ -155,16 +155,18 @@ nat_ctx = ip_fw3_nat_ctx[mycpuid]; (*args)->rule = *f; - nat = ((ipfw_insn_nat *)cmd)->nat; + /* + * DF-0572: do NOT cache the per-CPU cfg_nat pointer in the shared + * rule instruction. Each CPU must resolve its OWN cfg_nat every + * time, otherwise all CPUs converge on one CPU's cfg_nat and race + * unsynchronized on its RB trees (and against that CPU's cleanup). + */ + nat_id = cmd->arg1; + nat = nat_ctx->nats[nat_id - 1]; if (nat == NULL) { - nat_id = cmd->arg1; - nat = nat_ctx->nats[nat_id - 1]; - if (nat == NULL) { - *cmd_val = IP_FW_DENY; - *cmd_ctl = IP_FW_CTL_DONE; - return; - } - ((ipfw_insn_nat *)cmd)->nat = nat; + *cmd_val = IP_FW_DENY; + *cmd_ctl = IP_FW_CTL_DONE; + return; } *cmd_val = ip_fw3_nat(*args, nat, (*args)->m); *cmd_ctl = IP_FW_CTL_NAT; |