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