diff --git a/sys/net/ipfw3/ip_fw3.c b/sys/net/ipfw3/ip_fw3.c --- a/sys/net/ipfw3/ip_fw3.c +++ b/sys/net/ipfw3/ip_fw3.c @@ -646,7 +646,19 @@ const struct ipfw_ioc_rule *ioc_rule; ioc_rule = fwmsg->ioc_rule; - // create rule by ioc_rule + /* create rule by ioc_rule + * DF-0475: validate act_ofs so ACTION_PTR(rule) cannot point past + * the cmd[] array. Without this, a root-installed rule with + * act_ofs >= cmd_len makes CHK_STATE / lookup_next_rule / + * ip_fw3_dummynet_io dereference adjacent kernel heap via + * ACTION_PTR = (uint32_t*)cmd + act_ofs. + */ + if (ioc_rule->act_ofs > ioc_rule->cmd_len) { + kprintf("ipfw3: refusing rule %d: act_ofs %u > cmd_len %u\n", + ioc_rule->rulenum, ioc_rule->act_ofs, ioc_rule->cmd_len); + netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); + return; + } rule = kmalloc(RULESIZE(ioc_rule), M_IPFW3, M_WAITOK | M_ZERO); rule->act_ofs = ioc_rule->act_ofs; rule->cmd_len = ioc_rule->cmd_len;