DragonFlyBSD Kernel Audit
DF-0741 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -234,6 +234,22 @@
 		return(IPPROTO_DONE);
 	}
 
+	/*
+	 * The mobile header is variable-length and is overlaid on the
+	 * head mbuf right after the outer IP header.  The bcopy below
+	 * slides the (post-mobile-header) payload over the mobile header,
+	 * so the head mbuf must hold at least ip_hl*4 + msiz bytes.
+	 * Without this check, m->m_len - msiz - (ip->ip_hl << 2) under-
+	 * flows (signed int) and is widened to size_t for bcopy(), causing
+	 * a near-2^64 over-read/over-write and an immediate kernel panic
+	 * (DF-0741).  Drop short / chained-mbuf packets that don't carry
+	 * the full mobile header in the head mbuf.
+	 */
+	if (m->m_len < (ip->ip_hl << 2) + msiz) {
+		m_freem(m);
+		return(IPPROTO_DONE);
+	}
+
 	bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) +
 	    (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2));
 	m->m_len -= msiz;