DF-3293 / fix.diff
--- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -760,11 +760,20 @@ /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX + * + * This must be a runtime check, not only a KASSERT: KASSERTs are + * compiled out of production (non-INVARIANTS) kernels, and packets + * can reach tcp_input() without ip_demux-side validation, e.g. + * decapsulated packets that keep a stale M_LENCHECKED (gre(4)) or + * IPv6 segments whose th_off was never validated at all. A forged + * th_off would otherwise make tlen negative and corrupt the segment + * processing state (or panic INVARIANTS kernels). */ off = th->th_off << 2; - /* already checked and pulled up in ip_demux() */ - KASSERT(off >= sizeof(struct tcphdr) && off <= tlen, - ("bad TCP data offset %d (tlen %d)", off, tlen)); + if (off < (int)sizeof(struct tcphdr) || off > tlen) { + ++tcpstat.tcps_rcvbadoff; + goto drop; + } tlen -= off; /* tlen is used instead of ti->ti_len */ if (off > sizeof(struct tcphdr)) { if (isipv6) { |