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 @@ -964,6 +964,24 @@ } ioc_rule = sopt->sopt_val; + /* + * Validate cmd_len / act_ofs against the data actually supplied. + * Without this a caller may set cmd_len=255 while sending only a + * few instruction words: krealloc() grows the buffer to 1020 bytes + * (uninitialised tail) and add_rule_dispatch() then bcopy()s + * cmd_len*4 bytes out of ioc_rule->cmd, over-reading ~36 bytes past + * the allocation and copying uninitialised heap into the rule. That + * garbage is leaked back to userland via IP_FW_GET and is also used + * as the filter_funcs[module][opcode] indices by ip_fw3_chk, yielding + * an out-of-bounds indirect function call. + */ + if (ioc_rule->cmd_len > IPFW_RULE_SIZE_MAX - + ((sizeof(*ioc_rule) - sizeof(ipfw_insn)) / sizeof(uint32_t)) || + ioc_rule->act_ofs >= ioc_rule->cmd_len || + size < IOC_RULESIZE(ioc_rule)) { + return EINVAL; + } + ip_fw3_add_rule(ioc_rule); return 0; }