⬢ DragonFlyBSD Kernel Audit
DF-3293 / fix.diff
← back to finding ↓ download raw
--- 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) {