⬢ DragonFlyBSD Kernel Audit
DF-3444 / fix.diff
← back to finding ↓ download raw
--- a/sys/net/bpf_filter.c
+++ b/sys/net/bpf_filter.c
@@ -363,18 +363,33 @@
 			continue;
 
 		case BPF_LD|BPF_MEM:
+			/*
+			 * Do not trust that the caller ran bpf_validate():
+			 * at least one in-kernel caller (ipfw3_layer4
+			 * check_bpf) executes user-installed programs that
+			 * never passed validation.  An out-of-range k here
+			 * is an arbitrary-offset kernel stack read/write.
+			 */
+			if (pc->k >= BPF_MEMWORDS)
+				return 0;
 			A = mem[pc->k];
 			continue;
 
 		case BPF_LDX|BPF_MEM:
+			if (pc->k >= BPF_MEMWORDS)
+				return 0;
 			X = mem[pc->k];
 			continue;
 
 		case BPF_ST:
+			if (pc->k >= BPF_MEMWORDS)
+				return 0;
 			mem[pc->k] = A;
 			continue;
 
 		case BPF_STX:
+			if (pc->k >= BPF_MEMWORDS)
+				return 0;
 			mem[pc->k] = X;
 			continue;
 
--- a/sys/net/ipfw3_layer4/ip_fw3_layer4.c
+++ b/sys/net/ipfw3_layer4/ip_fw3_layer4.c
@@ -198,6 +198,18 @@
 	struct mbuf *m = (*args)->m;
 	ipfw_insn_bpf *bpf = (ipfw_insn_bpf *)cmd;
 	*cmd_ctl = IP_FW_CTL_NO;
+
+	/*
+	 * The rule instruction stream is copied into the kernel verbatim
+	 * (ip_fw3.c add_rule_dispatch bcopy) and never validated.  A bogus
+	 * program here is an arbitrary-offset kernel stack read/write in
+	 * bpf_filter().  Reject anything bpf_validate() would reject.
+	 */
+	if (!bpf_validate(bpf->bf_insn, (int)bpf->bf_len)) {
+		*cmd_val = IP_FW_NOT_MATCH;
+		return;
+	}
+
 	slen = bpf_filter(bpf->bf_insn, (u_char *)m, m_lengthm(m, NULL), 0);
 	if (slen != 0)
 		*cmd_val = IP_FW_MATCH;