DF-0747 / fix.diff
diff --git a/sys/net/ipfw3_layer4/ip_fw3_layer4.c b/sys/net/ipfw3_layer4/ip_fw3_layer4.c --- a/sys/net/ipfw3_layer4/ip_fw3_layer4.c +++ b/sys/net/ipfw3_layer4/ip_fw3_layer4.c @@ -169,20 +169,22 @@ /* * match TCP packets which have all tcpflag except SYN. + * + * Use the cached f_id.flags (populated only for first/unfragmented TCP + * segments in ip_fw3_chk() at the offset==0 branch). Non-first fragments + * have no TCP header in the mbuf, so re-reading L3HDR(tcphdr,ip)->th_flags + * would either dereference attacker-controlled fragment data or over-read + * past valid m_len into the mbuf backing store. */ void check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) { struct ipfw_flow_id *fid; - struct mbuf *m = (*args)->m; - struct ip *ip = mtod(m, struct ip *); *cmd_ctl = IP_FW_CTL_NO; fid = &(*args)->f_id; if (fid->proto == IPPROTO_TCP) { - /* offset == 0 && */ - if ((L3HDR(struct tcphdr, ip)->th_flags & - (TH_RST | TH_ACK | TH_SYN)) != TH_SYN) { + if ((fid->flags & (TH_RST | TH_ACK | TH_SYN)) != TH_SYN) { *cmd_val = IP_FW_MATCH; return; } |