--- 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;