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