⬢ DragonFlyBSD Kernel Audit
DF-3260 / fix.diff
← back to finding ↓ download raw
--- 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: