DF-3260 / fix.diff
--- a/sys/net/ipfw/ip_fw2.c +++ b/sys/net/ipfw/ip_fw2.c @@ -5312,6 +5312,8 @@ { int l, cmdlen = 0; int have_action = 0; + int act_ofs_ok = 0; + uint16_t act_ofs = rule->act_ofs; ipfw_insn *cmd; *rule_flags = 0; @@ -5334,11 +5336,26 @@ } /* + * act_ofs is used by ipfw_chk(), ipfw_log(), clear_counters() + * and ipfw_dummynet_io() to locate the action instruction + * (ACTION_PTR()). It must be within the command chain and it + * must land on an instruction boundary, otherwise the kernel + * would read and write out of bounds of the rule allocation. + */ + if (act_ofs >= rule->cmd_len) { + kprintf("ipfw: invalid act_ofs %u (cmd_len %u)\n", + act_ofs, rule->cmd_len); + return EINVAL; + } + + /* * Now go for the individual checks. Very simple ones, basically only * instruction sizes. */ for (l = rule->cmd_len, cmd = rule->cmd; l > 0; l -= cmdlen, cmd += cmdlen) { + if (rule->cmd_len - l == act_ofs) + act_ofs_ok = 1; cmdlen = F_LEN(cmd); if (cmdlen > l) { kprintf("ipfw: opcode %d size truncated\n", @@ -5542,6 +5559,11 @@ kprintf("ipfw: missing action\n"); return EINVAL; } + if (!act_ofs_ok) { + kprintf("ipfw: act_ofs %u not on instruction boundary\n", + act_ofs); + return EINVAL; + } return 0; bad_size: |