kern/168190: [pf] panic when using pf and route-to (maybe: bad fragment handling?)

Daniel Hartmeier daniel at benzedrine.cx
Tue May 29 06:49:30 UTC 2012


On Sun, May 27, 2012 at 06:30:09PM +0000, Joerg Pulz wrote:

>  i've seen 12 more "pf_route: m0->m_len < sizeof(struct ip)" messages since the system is running after adding your patch, but no panic.
>  Is there another place in the code where i can add an additional check?

Yes, the following patch adds more checks to pf.

Kind regards,
Daniel
-------------- next part --------------
Index: sys/contrib/pf/net/pf.c
===================================================================
RCS file: /home/ncvs/src/sys/contrib/pf/net/pf.c,v
retrieving revision 1.78.2.6
diff -u -r1.78.2.6 pf.c
--- sys/contrib/pf/net/pf.c	29 Feb 2012 09:47:26 -0000	1.78.2.6
+++ sys/contrib/pf/net/pf.c	29 May 2012 06:39:54 -0000
@@ -2560,6 +2560,7 @@
 	case AF_INET:
 #ifdef __FreeBSD__
 		/* icmp_error() expects host byte ordering */
+		ASSERT_NET_BYTE_ORDER(m0);
 		ip = mtod(m0, struct ip *);
 		NTOHS(ip->ip_len);
 		NTOHS(ip->ip_off);
@@ -5894,6 +5895,13 @@
 	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
 		panic("pf_route: invalid parameters");
 
+	ASSERT_NET_BYTE_ORDER(*m);
+
+	if ((*m)->m_pkthdr.len < sizeof(struct ip) ||
+	    (*m)->m_len < sizeof(struct ip))
+		panic("pf_route: 1: (*m)->m_pkthdr.len %d, (*m)->m_len %d",
+		    (int)(*m)->m_pkthdr.len, (int)(*m)->m_len);
+
 #ifdef __FreeBSD__
 	if (pd->pf_mtag->routed++ > 3) {
 #else
@@ -5917,9 +5925,14 @@
 		m0 = *m;
 	}
 
+	if (m0->m_pkthdr.len < sizeof(struct ip) ||
+	    m0->m_len < sizeof(struct ip))
+		panic("pf_route: 2: m0->m_pkthdr.len %d, m0->m_len %d",
+		    (int)m0->m_pkthdr.len, (int)m0->m_len);
+
 	if (m0->m_len < sizeof(struct ip)) {
 		DPFPRINTF(PF_DEBUG_URGENT,
-		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
+		    ("pf_route: a: m0->m_len < sizeof(struct ip)\n"));
 		goto bad;
 	}
 
@@ -5975,8 +5988,14 @@
 	if (ifp == NULL)
 		goto bad;
 
+	if (m0->m_pkthdr.len < sizeof(struct ip) ||
+	    m0->m_len < sizeof(struct ip))
+		panic("pf_route: 2: m0->m_pkthdr.len %d, m0->m_len %d",
+		    (int)m0->m_pkthdr.len, (int)m0->m_len);
+
 	if (oifp != ifp) {
 #ifdef __FreeBSD__
+		ASSERT_NET_BYTE_ORDER(m0);
 		PF_UNLOCK();
 		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
 			PF_LOCK();
@@ -5992,12 +6011,18 @@
 		else if (m0 == NULL)
 			goto done;
 #endif
+		if (m0->m_pkthdr.len < sizeof(struct ip) ||
+		    m0->m_len < sizeof(struct ip))
+			panic("pf_route: 3: m0->m_pkthdr.len %d, m0->m_len %d",
+			    (int)m0->m_pkthdr.len, (int)m0->m_len);
+
 		if (m0->m_len < sizeof(struct ip)) {
 			DPFPRINTF(PF_DEBUG_URGENT,
-			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
+			    ("pf_route: b: m0->m_len < sizeof(struct ip)\n"));
 			goto bad;
 		}
 		ip = mtod(m0, struct ip *);
+		ASSERT_NET_BYTE_ORDER(m0);
 	}
 
 #ifdef __FreeBSD__
@@ -6008,6 +6033,7 @@
 		/*
 		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
 		 */
+		ASSERT_NET_BYTE_ORDER(m0);
 		NTOHS(ip->ip_len);
 		NTOHS(ip->ip_off);	/* XXX: needed? */
 		in_delayed_cksum(m0);
@@ -6017,6 +6043,8 @@
 	}
 	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
 
+	ASSERT_NET_BYTE_ORDER(m0);
+
 	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
 	    (ifp->if_hwassist & CSUM_FRAGMENT &&
 	    ((ip->ip_off & htons(IP_DF)) == 0))) {
@@ -6104,6 +6132,7 @@
 		if (r->rt != PF_DUPTO) {
 #ifdef __FreeBSD__
 			/* icmp_error() expects host byte ordering */
+			ASSERT_NET_BYTE_ORDER(m0);
 			NTOHS(ip->ip_len);
 			NTOHS(ip->ip_off);
 			PF_UNLOCK();
@@ -6124,6 +6153,7 @@
 	/*
 	 * XXX: is cheaper + less error prone than own function
 	 */
+	ASSERT_NET_BYTE_ORDER(m0);
 	NTOHS(ip->ip_len);
 	NTOHS(ip->ip_off);
 	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
@@ -6672,6 +6702,8 @@
 #endif /* DIAGNOSTIC */
 #endif
 
+	ASSERT_NET_BYTE_ORDER(m);
+
 	if (m->m_pkthdr.len < (int)sizeof(*h)) {
 		action = PF_DROP;
 		REASON_SET(&reason, PFRES_SHORT);
@@ -6679,6 +6711,11 @@
 		goto done;
 	}
 
+	if (m->m_pkthdr.len < sizeof(struct ip) ||
+	    m->m_len < sizeof(struct ip))
+		panic("pf_test: 1: m->m_pkthdr.len %d, m->m_len %d",
+		    (int)m->m_pkthdr.len, (int)m->m_len);
+
 #ifdef __FreeBSD__
 	if (m->m_flags & M_SKIP_FIREWALL) {
 		PF_UNLOCK();
@@ -6711,6 +6748,11 @@
 	m = *m0;	/* pf_normalize messes with m0 */
 	h = mtod(m, struct ip *);
 
+	if (m->m_pkthdr.len < sizeof(struct ip) ||
+	    m->m_len < sizeof(struct ip))
+		panic("pf_test: 2: m->m_pkthdr.len %d, m->m_len %d",
+		    (int)m->m_pkthdr.len, (int)m->m_len);
+
 	off = h->ip_hl << 2;
 	if (off < (int)sizeof(*h)) {
 		action = PF_DROP;
@@ -6740,6 +6782,11 @@
 		goto done;
 	}
 
+	if (m->m_pkthdr.len < sizeof(struct ip) ||
+	    m->m_len < sizeof(struct ip))
+		panic("pf_test: 3: m->m_pkthdr.len %d, m->m_len %d",
+		    (int)m->m_pkthdr.len, (int)m->m_len);
+
 	switch (h->ip_p) {
 
 	case IPPROTO_TCP: {
@@ -6891,6 +6938,11 @@
 	}
 
 done:
+	if (m->m_pkthdr.len < sizeof(struct ip) ||
+	    m->m_len < sizeof(struct ip))
+		panic("pf_test: 4: m->m_pkthdr.len %d, m->m_len %d",
+		    (int)m->m_pkthdr.len, (int)m->m_len);
+
 	if (action == PF_PASS && h->ip_hl > 5 &&
 	    !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) {
 		action = PF_DROP;
@@ -6935,6 +6987,11 @@
 	}
 #endif /* ALTQ */
 
+	if (m->m_pkthdr.len < sizeof(struct ip) ||
+	    m->m_len < sizeof(struct ip))
+		panic("pf_test: 5: m->m_pkthdr.len %d, m->m_len %d",
+		    (int)m->m_pkthdr.len, (int)m->m_len);
+
 	/*
 	 * connections redirected to loopback should not match sockets
 	 * bound specifically to loopback due to security implications,
@@ -6996,6 +7053,11 @@
 	}
 #endif
 
+	if (m->m_pkthdr.len < sizeof(struct ip) ||
+	    m->m_len < sizeof(struct ip))
+		panic("pf_test: 6: m->m_pkthdr.len %d, m->m_len %d",
+		    (int)m->m_pkthdr.len, (int)m->m_len);
+
 	if (log) {
 		struct pf_rule *lr;
 
@@ -7069,8 +7131,14 @@
 		break;
 	default:
 		/* pf_route can free the mbuf causing *m0 to become NULL */
-		if (r->rt)
+		if (r->rt) {
+			if ((*m0)->m_pkthdr.len < sizeof(struct ip) ||
+			    (*m0)->m_len < sizeof(struct ip))
+				panic("pf_test: 7: m0->m_pkthdr.len %d, "
+				    "m0->m_len %d", (int)(*m0)->m_pkthdr.len,
+				    (int)(*m0)->m_len);
 			pf_route(m0, r, dir, kif->pfik_ifp, s, &pd);
+		}
 		break;
 	}
 #ifdef __FreeBSD__


More information about the freebsd-pf mailing list