Date: Tue, 22 May 2012 17:06:04 +0200 From: Daniel Hartmeier <daniel@benzedrine.cx> To: Joerg Pulz <Joerg.Pulz@frm2.tum.de> Cc: freebsd-pf@freebsd.org Subject: Re: kern/168190: [pf] panic when using pf and route-to (maybe: bad fragment handling?) Message-ID: <20120522150603.GF29536@insomnia.benzedrine.cx> In-Reply-To: <201205221200.q4MC0Gtg085514@freefall.freebsd.org> References: <201205221200.q4MC0Gtg085514@freefall.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
If you have the chance, please try the patch below. It adds byte order checks all over the place, hoping for a panic closer to the source of the problem. Daniel Index: sys/sys/mbuf.h =================================================================== RCS file: /home/ncvs/src/sys/sys/mbuf.h,v retrieving revision 1.242.2.1 diff -u -r1.242.2.1 mbuf.h --- sys/sys/mbuf.h 23 Sep 2011 00:51:37 -0000 1.242.2.1 +++ sys/sys/mbuf.h 22 May 2012 14:15:00 -0000 @@ -824,6 +824,20 @@ /* Compatibility with 4.3. */ #define m_copy(m, o, l) m_copym((m), (o), (l), M_DONTWAIT) +#define ASSERT_NET_BYTE_ORDER(m) do { \ + struct ip *ip = mtod((m), struct ip *); \ + if (ip->ip_len != htons(ip->ip_len) && \ + ip->ip_len == (m)->m_pkthdr.len) \ + panic("ASSERT_NET_BYTE_ORDER"); \ +} while(0) + +#define ASSERT_HOST_BYTE_ORDER(m) do { \ + struct ip *ip = mtod((m), struct ip *); \ + if (ip->ip_len != htons(ip->ip_len) && \ + ntohs(ip->ip_len) == (m)->m_pkthdr.len) \ + panic("ASSERT_NET_BYTE_ORDER"); \ +} while(0) + extern int max_datalen; /* MHLEN - max_hdr */ extern int max_hdr; /* Largest link + protocol header */ extern int max_linkhdr; /* Largest link-level header */ 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 22 May 2012 14:39:04 -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,8 @@ (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route: invalid parameters"); + ASSERT_NET_BYTE_ORDER(*m); + #ifdef __FreeBSD__ if (pd->pf_mtag->routed++ > 3) { #else @@ -5977,6 +5980,7 @@ 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(); @@ -5998,6 +6002,7 @@ goto bad; } ip = mtod(m0, struct ip *); + ASSERT_NET_BYTE_ORDER(m0); } #ifdef __FreeBSD__ @@ -6008,6 +6013,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 +6023,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 +6112,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 +6133,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 +6682,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); Index: sys/contrib/pf/net/pf_ioctl.c =================================================================== RCS file: /home/ncvs/src/sys/contrib/pf/net/pf_ioctl.c,v retrieving revision 1.50.2.4 diff -u -r1.50.2.4 pf_ioctl.c --- sys/contrib/pf/net/pf_ioctl.c 29 Feb 2012 09:47:26 -0000 1.50.2.4 +++ sys/contrib/pf/net/pf_ioctl.c 22 May 2012 14:37:44 -0000 @@ -4121,6 +4121,7 @@ if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { /* if m_pkthdr.len is less than ip header, pf will handle. */ + ASSERT_HOST_BYTE_ORDER(*m); h = mtod(*m, struct ip *); HTONS(h->ip_len); HTONS(h->ip_off); @@ -4134,6 +4135,7 @@ } if (*m != NULL) { /* pf_test can change ip header location */ + ASSERT_NET_BYTE_ORDER(*m); h = mtod(*m, struct ip *); NTOHS(h->ip_len); NTOHS(h->ip_off); @@ -4163,6 +4165,7 @@ } if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { /* if m_pkthdr.len is less than ip header, pf will handle. */ + ASSERT_HOST_BYTE_ORDER(*m); h = mtod(*m, struct ip *); HTONS(h->ip_len); HTONS(h->ip_off); @@ -4176,6 +4179,7 @@ } if (*m != NULL) { /* pf_test can change ip header location */ + ASSERT_NET_BYTE_ORDER(*m); h = mtod(*m, struct ip *); NTOHS(h->ip_len); NTOHS(h->ip_off); Index: sys/contrib/pf/net/pf_norm.c =================================================================== RCS file: /home/ncvs/src/sys/contrib/pf/net/pf_norm.c,v retrieving revision 1.21.2.2 diff -u -r1.21.2.2 pf_norm.c --- sys/contrib/pf/net/pf_norm.c 29 Feb 2012 09:47:26 -0000 1.21.2.2 +++ sys/contrib/pf/net/pf_norm.c 22 May 2012 14:41:02 -0000 @@ -1190,6 +1190,8 @@ if (hlen < (int)sizeof(struct ip)) goto drop; + ASSERT_NET_BYTE_ORDER(m); + if (hlen > ntohs(h->ip_len)) goto drop; Index: sys/net/if_bridge.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_bridge.c,v retrieving revision 1.144.2.2 diff -u -r1.144.2.2 if_bridge.c --- sys/net/if_bridge.c 17 Mar 2012 12:11:53 -0000 1.144.2.2 +++ sys/net/if_bridge.c 22 May 2012 14:44:14 -0000 @@ -3142,6 +3142,7 @@ */ ip = mtod(*mp, struct ip *); + ASSERT_NET_BYTE_ORDER(*mp); ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); @@ -3195,6 +3196,7 @@ if (ip == NULL) goto bad; } + ASSERT_HOST_BYTE_ORDER(*mp); ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); ip->ip_sum = 0; @@ -3332,6 +3334,7 @@ } /* Retrieve the packet length. */ + ASSERT_NET_BYTE_ORDER(m); len = ntohs(ip->ip_len); /* Index: sys/net/if_enc.c =================================================================== RCS file: /home/ncvs/src/sys/net/if_enc.c,v retrieving revision 1.17.2.1 diff -u -r1.17.2.1 if_enc.c --- sys/net/if_enc.c 23 Sep 2011 00:51:37 -0000 1.17.2.1 +++ sys/net/if_enc.c 22 May 2012 14:43:27 -0000 @@ -274,6 +274,7 @@ * before calling the firewall, swap fields the same as * IP does. here we assume the header is contiguous */ + ASSERT_NET_BYTE_ORDER(*mp); ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); @@ -284,6 +285,7 @@ break; /* restore byte ordering */ + ASSERT_HOST_BYTE_ORDER(*mp); ip = mtod(*mp, struct ip *); ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); Index: sys/net/pfil.c =================================================================== RCS file: /home/ncvs/src/sys/net/pfil.c,v retrieving revision 1.19.2.1 diff -u -r1.19.2.1 pfil.c --- sys/net/pfil.c 23 Sep 2011 00:51:37 -0000 1.19.2.1 +++ sys/net/pfil.c 22 May 2012 14:49:24 -0000 @@ -46,6 +46,8 @@ #include <net/if.h> #include <net/pfil.h> +#include <netinet/in.h> +#include <netinet/ip.h> static struct mtx pfil_global_lock; @@ -79,10 +81,12 @@ for (pfh = pfil_hook_get(dir, ph); pfh != NULL; pfh = TAILQ_NEXT(pfh, pfil_link)) { if (pfh->pfil_func != NULL) { + ASSERT_HOST_BYTE_ORDER(m); rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, inp); if (rv != 0 || m == NULL) break; + ASSERT_HOST_BYTE_ORDER(m); } } PFIL_RUNLOCK(ph, &rmpt); Index: sys/netinet/ip_divert.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_divert.c,v retrieving revision 1.173.2.1 diff -u -r1.173.2.1 ip_divert.c --- sys/netinet/ip_divert.c 23 Sep 2011 00:51:37 -0000 1.173.2.1 +++ sys/netinet/ip_divert.c 22 May 2012 14:27:15 -0000 @@ -207,6 +207,7 @@ (m = m_pullup(m, sizeof(struct ip))) == 0) return; ip = mtod(m, struct ip *); + ASSERT_NET_BYTE_ORDER(m); /* Delayed checksums are currently not compatible with divert. */ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { @@ -396,6 +397,7 @@ /* Convert fields to host order for ip_output() */ ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); + ASSERT_HOST_BYTE_ORDER(m); break; #ifdef INET6 case IPV6_VERSION >> 4: Index: sys/netinet/ip_fastfwd.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_fastfwd.c,v retrieving revision 1.57.2.1 diff -u -r1.57.2.1 ip_fastfwd.c --- sys/netinet/ip_fastfwd.c 23 Sep 2011 00:51:37 -0000 1.57.2.1 +++ sys/netinet/ip_fastfwd.c 22 May 2012 14:46:00 -0000 @@ -179,6 +179,7 @@ M_ASSERTVALID(m); M_ASSERTPKTHDR(m); + ASSERT_NET_BYTE_ORDER(m); bzero(&ro, sizeof(ro)); @@ -343,6 +344,7 @@ /* * Convert to host representation */ + ASSERT_NET_BYTE_ORDER(m); ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); @@ -361,6 +363,7 @@ M_ASSERTVALID(m); M_ASSERTPKTHDR(m); + ASSERT_HOST_BYTE_ORDER(m); ip = mtod(m, struct ip *); /* m may have changed by pfil hook */ dest.s_addr = ip->ip_dst.s_addr; @@ -442,12 +445,14 @@ if (!PFIL_HOOKED(&V_inet_pfil_hook)) goto passout; + ASSERT_HOST_BYTE_ORDER(m); if (pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, NULL) || m == NULL) { goto drop; } M_ASSERTVALID(m); M_ASSERTPKTHDR(m); + ASSERT_HOST_BYTE_ORDER(m); ip = mtod(m, struct ip *); dest.s_addr = ip->ip_dst.s_addr; @@ -511,6 +516,7 @@ goto consumed; } + ASSERT_HOST_BYTE_ORDER(m); #ifndef ALTQ /* * Check if there is enough space in the interface queue Index: sys/netinet/ip_icmp.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v retrieving revision 1.145.2.2 diff -u -r1.145.2.2 ip_icmp.c --- sys/netinet/ip_icmp.c 19 Mar 2012 20:49:16 -0000 1.145.2.2 +++ sys/netinet/ip_icmp.c 22 May 2012 14:31:17 -0000 @@ -185,6 +185,7 @@ unsigned icmplen, icmpelen, nlen; KASSERT((u_int)type <= ICMP_MAXTYPE, ("%s: illegal ICMP type", __func__)); + ASSERT_HOST_BYTE_ORDER(n); #ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_error(%p, %x, %d)\n", oip, type, code); @@ -336,6 +337,7 @@ void (*ctlfunc)(int, struct sockaddr *, void *); int fibnum; + ASSERT_HOST_BYTE_ORDER(m); /* * Locate icmp structure in mbuf, and check * that not corrupted and of at least minimum length. @@ -866,6 +868,7 @@ register int hlen; register struct icmp *icp; + ASSERT_HOST_BYTE_ORDER(m); hlen = ip->ip_hl << 2; m->m_data += hlen; m->m_len -= hlen; Index: sys/netinet/ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.393.2.3 diff -u -r1.393.2.3 ip_input.c --- sys/netinet/ip_input.c 19 Mar 2012 20:49:16 -0000 1.393.2.3 +++ sys/netinet/ip_input.c 22 May 2012 14:23:45 -0000 @@ -385,6 +385,7 @@ struct in_addr odst; /* original dst address */ M_ASSERTPKTHDR(m); + ASSERT_NET_BYTE_ORDER(m); if (m->m_flags & M_FASTFWD_OURS) { /* @@ -467,6 +468,7 @@ goto bad; } ip->ip_off = ntohs(ip->ip_off); + ASSERT_HOST_BYTE_ORDER(m); /* * Check that the amount of data in the buffers @@ -1371,6 +1373,7 @@ struct route ro; int error, type = 0, code = 0, mtu = 0; + ASSERT_HOST_BYTE_ORDER(m); if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) { IPSTAT_INC(ips_cantforward); m_freem(m); Index: sys/netinet/ip_ipsec.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_ipsec.c,v retrieving revision 1.28.2.1 diff -u -r1.28.2.1 ip_ipsec.c --- sys/netinet/ip_ipsec.c 23 Sep 2011 00:51:37 -0000 1.28.2.1 +++ sys/netinet/ip_ipsec.c 22 May 2012 14:25:41 -0000 @@ -346,6 +346,7 @@ (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP; } #endif + ASSERT_HOST_BYTE_ORDER(*m); ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); Index: sys/netinet/ip_mroute.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_mroute.c,v retrieving revision 1.161.2.2 diff -u -r1.161.2.2 ip_mroute.c --- sys/netinet/ip_mroute.c 28 Mar 2012 12:45:35 -0000 1.161.2.2 +++ sys/netinet/ip_mroute.c 22 May 2012 14:32:54 -0000 @@ -1496,6 +1496,7 @@ vifi_t vifi; int plen = ip->ip_len; + ASSERT_HOST_BYTE_ORDER(m); VIF_LOCK_ASSERT(); /* @@ -2375,6 +2376,8 @@ struct mbuf *mb_copy = NULL; int mtu; + ASSERT_HOST_BYTE_ORDER(m); + /* Take care of delayed checksums */ if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(m); Index: sys/netinet/ip_output.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v retrieving revision 1.329.2.2 diff -u -r1.329.2.2 ip_output.c --- sys/netinet/ip_output.c 10 Nov 2011 20:28:30 -0000 1.329.2.2 +++ sys/netinet/ip_output.c 22 May 2012 14:47:14 -0000 @@ -133,6 +133,7 @@ int no_route_but_check_spd = 0; #endif M_ASSERTPKTHDR(m); + ASSERT_HOST_BYTE_ORDER(m); if (inp != NULL) { INP_LOCK_ASSERT(inp); @@ -434,6 +435,8 @@ } } + ASSERT_HOST_BYTE_ORDER(m); + /* * Verify that we have any chance at all of being able to queue the * packet or packet fragments, unless ALTQ is enabled on the given @@ -505,6 +508,7 @@ /* Run through list of hooks for output packets. */ odst.s_addr = ip->ip_dst.s_addr; + ASSERT_HOST_BYTE_ORDER(m); error = pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, inp); if (error != 0 || m == NULL) goto done; @@ -596,6 +600,7 @@ * If small enough for interface, or the interface will take * care of the fragmentation for us, we can just send directly. */ + ASSERT_HOST_BYTE_ORDER(m); if (ip->ip_len <= mtu || (m->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0 || ((ip->ip_off & IP_DF) == 0 && (ifp->if_hwassist & CSUM_FRAGMENT))) { @@ -628,6 +633,7 @@ * to avoid confusing lower layers. */ m->m_flags &= ~(M_PROTOFLAGS); + ASSERT_NET_BYTE_ORDER(m); error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro); goto done; @@ -716,6 +722,8 @@ if (len < 8) return EMSGSIZE; + ASSERT_HOST_BYTE_ORDER(m0); + /* * If the interface will not calculate checksums on * fragmented packets, then do it here.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120522150603.GF29536>