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

Joerg Pulz Joerg.Pulz at frm2.tum.de
Mon May 21 18:49:36 UTC 2012


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Content-ID: <alpine.BSF.2.00.1205212044250.74709 at unqrf.nqzva.sez2>

On Mon, 21 May 2012, Daniel Hartmeier wrote:

> On Mon, May 21, 2012 at 02:20:04PM +0000, Joerg Pulz wrote:
>
>>  ext_if="bge0"
>>  int_if="bge1"
>>  vpn_net="10.1.1.0/24"
>>  srv_net="172.16.1.0/24"
>>  gw_addr="172.16.1.254"
>>
>>  scrub in all
>>
>>  pass out on $ext_if route-to ($int_if $gw_addr) from $vpn_net to any keep state
>>  pass out on $int_if route-to ($int_if $gw_addr) from $vpn_net to $srv_net keep state
>
> So something from $vpn_net comes in, gets routed to the default gateway
> (on $ext_if side), attempts to pass out on $ext_if, matches the first
> rule, route-to applies, packet gets re-routed to $gw_addr, passes out
> on $int_if, matches the second rule, double route-to.
>
> All you need to do is prevent the second rule from applying for packets
> where the first rule matched, like with tags:
>
>  pass out on $ext_if route-to ($int_if $gw_addr) from $vpn_net to any keep state tag from_vpn
>  pass out on $int_if route-to ($int_if $gw_addr) from $vpn_net to $srv_net keep state
>  pass out on $int_if from $vpn_net to $srv_net keep state tagged from_vpn
>
> i.e. you add 'tag from_vpn' to the first rule, so packets matching it
> get tagged, then you add a third rule without route-to that applies to
> tagged packets, which wins last-match for such packets.
>
> Or, instead of adding a third rule, add '! tagged from_vpn' to the
> second rule, if tagged packets can still pass out on $int_if by another
> rule.

Daniel,

thanks again.
There is one main question left for me.
How could a packet which is directed to a host in $srv_net (and $srv_net 
is the same broadcast domain as $int_if) ever leave through $ext_if and 
make the first route-to match and therefor lead to a double route-to?

Regarding your other mail with the reproduce instructions

> BTW, if the theory is correct, you should be able to reproduce the
> problem by sending a packet in from $vpn_net to a host in $srv_net
> of size 334 (=306+28), e.g. with
>
>  $ ping -s 306 172.16.1.1

I tried this, but it did no harm to the system at all. Packets where 
flowing as they should and answers came back.

PF ruleset is still unchanged, no tagging.
Meanwhile the system panic'ed again, and this time there is no double 
route-to involved at all. kgdb(1) output below.
If your assumption in your first response is right:

> It looks like the byte order of ip_len is wrong, htons(334) = 19969,
> triggering fragmentation (334 < if_mtu, but 19969 > if_mtu).

Then it should read htons(175) = 44800
(175 < if_mtu, but 44800 > if_mtu")

But where is it coming from if double route-to can't be the culprit in 
this case?

Any thoughts on this?

Kind regards
Joerg

### kgdb.out2

GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "amd64-marcel-freebsd"...

Unread portion of the kernel message buffer:
panic: m_copym, offset > size of mbuf chain
cpuid = 1
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2a
kdb_backtrace() at kdb_backtrace+0x37
panic() at panic+0x182
m_copym() at m_copym+0x280
ip_fragment() at ip_fragment+0x1e5
pf_route() at pf_route+0x75c
pf_test() at pf_test+0xc29
pf_check_out() at pf_check_out+0x3a
pfil_run_hooks() at pfil_run_hooks+0xd2
ip_output() at ip_output+0x655
ip_forward() at ip_forward+0x175
ip_input() at ip_input+0x5fd
swi_net() at swi_net+0x15a
intr_event_execute_handlers() at intr_event_execute_handlers+0x66
ithread_loop() at ithread_loop+0xaf
fork_exit() at fork_exit+0x12a
fork_trampoline() at fork_trampoline+0xe
- --- trap 0, rip = 0, rsp = 0xffffff8000241d00, rbp = 0 ---
KDB: enter: panic
Dumping 628 out of 4077 MB:..3%..11%..21%..31%..41%..51%..62%..72%..82%..92%

Reading symbols from /boot/kernel/geom_mirror.ko...Reading symbols from /boot/kernel/geom_mirror.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/geom_mirror.ko
Reading symbols from /boot/kernel/ipmi.ko...Reading symbols from /boot/kernel/ipmi.ko.symbols...done.
done.
Loaded symbols for /boot/kernel/ipmi.ko
#0  doadump (textdump=0) at pcpu.h:224
224		__asm("movq %%gs:0,%0" : "=r" (td));
(kgdb) up 10
#10 0xffffffff806e9079 in m_copym (m=0x0, off0=1500, len=1480, wait=1)
     at /usr/src/sys/kern/uipc_mbuf.c:541
541			KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain"));
(kgdb) list
536		KASSERT(len >= 0, ("m_copym, negative len %d", len));
537		MBUF_CHECKSLEEP(wait);
538		if (off == 0 && m->m_flags & M_PKTHDR)
539			copyhdr = 1;
540		while (off > 0) {
541			KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain"));
542			if (off < m->m_len)
543				break;
544			off -= m->m_len;
545			m = m->m_next;
(kgdb) p off
$1 = 1325
(kgdb) up
#11 0xffffffff8077fe1f in ip_fragment (ip=0xfffffe0173b1fc74,
     m_frag=0xffffff8000241658, mtu=) at /usr/src/sys/netinet/ip_output.c:816
816			m->m_next = m_copym(m0, off, len, M_DONTWAIT);
(kgdb) list
811				len = ip->ip_len - off;
812				m->m_flags |= M_LASTFRAG;
813			} else
814				mhip->ip_off |= IP_MF;
815			mhip->ip_len = htons((u_short)(len + mhlen));
816			m->m_next = m_copym(m0, off, len, M_DONTWAIT);
817			if (m->m_next == NULL) {	/* copy failed */
818				m_free(m);
819				error = ENOBUFS;	/* ??? */
820				IPSTAT_INC(ips_odropped);
(kgdb) p *m0
$2 = {m_hdr = {mh_next = 0xfffffe0005b70000, mh_nextpkt = 0x0,
     mh_data = 0xfffffe0173b1fc74 "E", mh_len = 60, mh_flags = 66, mh_type = 1,
     pad = "­ÞÞÀ­Þ"}, M_dat = {MH = {MH_pkthdr = {rcvif = 0xfffffe0003001800,
         header = 0x0, len = 175, flowid = 0, csum_flags = 1,
         csum_data = 59883, tso_segsz = 0, PH_vt = {vt_vtag = 0, vt_nrecs = 0},
         tags = {slh_first = 0xfffffe00058c3840}}, MH_dat = {MH_ext = {
           ext_buf = 0xd29300ec0045 <Address 0xd29300ec0045 out of bounds>,
           ext_free = 0xd29300af0045, ext_arg1 = 0xba41965002280437,
           ext_arg2 = 0xaf00004557b3bb81, ext_size = 11615,
           ref_cnt = 0x240119ac02079b0a, ext_type = 1740374787},
         MH_databuf = "E\000ì\000\223Ò\000\000E\000¯\000\223Ò\000\0007\004(\002P\226Aº\201»³WE\000\000¯_-\000\000\177\001\034G\n\233\a\002¬\031\001$\003\003¼g\000\000\000\000E\000\000\223\215:\000\000>\0210F¬\031\001$\n\233\a\002\0005äv\000\177\vC\200\035\201\200\000\001\000\002\000\002\000\000ÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­Þ"}},
     M_databuf = "\000\030\000\003\000þÿÿ\000\000\000\000\000\000\000\000¯\000\000\000\000\000\000\000\001\000\000\000ëé\000\000\000\000\000\000ÞÀ­Þ@8\214\005\000þÿÿE\000ì\000\223Ò\000\000E\000¯\000\223Ò\000\0007\004(\002P\226Aº\201»³WE\000\000¯_-\000\000\177\001\034G\n\233\a\002¬\031\001$\003\003¼g\000\000\000\000E\000\000\223\215:\000\000>\0210F¬\031\001$\n\233\a\002\0005äv\000\177\vC\200\035\201\200\000\001\000\002\000\002\000\000ÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­Þ"...}}
(kgdb) p off
$3 = 1500
(kgdb) p len
$4 = 1480
(kgdb) p hlen
$5 = 20
(kgdb) up
#12 0xffffffff8032842a in pf_route (m=0xffffff80002418e8,
     r=0xfffffe0005d87750, dir=) at /usr/src/sys/contrib/pf/net/pf.c:6138
6138		error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
(kgdb) list
6133		/*
6134		 * XXX: is cheaper + less error prone than own function
6135		 */
6136		NTOHS(ip->ip_len);
6137		NTOHS(ip->ip_off);
6138		error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
6139	#else
6140		error = ip_fragment(m0, ifp, ifp->if_mtu);
6141	#endif
6142		if (error) {
(kgdb) p *ip
$6 = {ip_hl = 5 '\005', ip_v = 4 '\004', ip_tos = 0 '\0', ip_len = 44800,
   ip_id = 11615, ip_off = 0, ip_ttl = 127 '\177', ip_p = 1 '\001',
   ip_sum = 18204, ip_src = {s_addr = 34052874}, ip_dst = {s_addr = 604051884}}
(kgdb) p *m0
$7 = {m_hdr = {mh_next = 0xfffffe0005b70000, mh_nextpkt = 0x0,
     mh_data = 0xfffffe0173b1fc74 "E", mh_len = 60, mh_flags = 66, mh_type = 1,
     pad = "­ÞÞÀ­Þ"}, M_dat = {MH = {MH_pkthdr = {rcvif = 0xfffffe0003001800,
         header = 0x0, len = 175, flowid = 0, csum_flags = 1,
         csum_data = 59883, tso_segsz = 0, PH_vt = {vt_vtag = 0, vt_nrecs = 0},
         tags = {slh_first = 0xfffffe00058c3840}}, MH_dat = {MH_ext = {
           ext_buf = 0xd29300ec0045 <Address 0xd29300ec0045 out of bounds>,
           ext_free = 0xd29300af0045, ext_arg1 = 0xba41965002280437,
           ext_arg2 = 0xaf00004557b3bb81, ext_size = 11615,
           ref_cnt = 0x240119ac02079b0a, ext_type = 1740374787},
         MH_databuf = "E\000ì\000\223Ò\000\000E\000¯\000\223Ò\000\0007\004(\002P\226Aº\201»³WE\000\000¯_-\000\000\177\001\034G\n\233\a\002¬\031\001$\003\003¼g\000\000\000\000E\000\000\223\215:\000\000>\0210F¬\031\001$\n\233\a\002\0005äv\000\177\vC\200\035\201\200\000\001\000\002\000\002\000\000ÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­Þ"}},
     M_databuf = "\000\030\000\003\000þÿÿ\000\000\000\000\000\000\000\000¯\000\000\000\000\000\000\000\001\000\000\000ëé\000\000\000\000\000\000ÞÀ­Þ@8\214\005\000þÿÿE\000ì\000\223Ò\000\000E\000¯\000\223Ò\000\0007\004(\002P\226Aº\201»³WE\000\000¯_-\000\000\177\001\034G\n\233\a\002¬\031\001$\003\003¼g\000\000\000\000E\000\000\223\215:\000\000>\0210F¬\031\001$\n\233\a\002\0005äv\000\177\vC\200\035\201\200\000\001\000\002\000\002\000\000ÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­Þ"...}}
(kgdb) p *m1
$8 = {m_hdr = {mh_next = 0xfffffe0005b70000, mh_nextpkt = 0x0,
     mh_data = 0xfffffe0173b1fc74 "E", mh_len = 60, mh_flags = 66, mh_type = 1,
     pad = "­ÞÞÀ­Þ"}, M_dat = {MH = {MH_pkthdr = {rcvif = 0xfffffe0003001800,
         header = 0x0, len = 175, flowid = 0, csum_flags = 1,
         csum_data = 59883, tso_segsz = 0, PH_vt = {vt_vtag = 0, vt_nrecs = 0},
         tags = {slh_first = 0xfffffe00058c3840}}, MH_dat = {MH_ext = {
           ext_buf = 0xd29300ec0045 <Address 0xd29300ec0045 out of bounds>,
           ext_free = 0xd29300af0045, ext_arg1 = 0xba41965002280437,
           ext_arg2 = 0xaf00004557b3bb81, ext_size = 11615,
           ref_cnt = 0x240119ac02079b0a, ext_type = 1740374787},
         MH_databuf = "E\000ì\000\223Ò\000\000E\000¯\000\223Ò\000\0007\004(\002P\226Aº\201»³WE\000\000¯_-\000\000\177\001\034G\n\233\a\002¬\031\001$\003\003¼g\000\000\000\000E\000\000\223\215:\000\000>\0210F¬\031\001$\n\233\a\002\0005äv\000\177\vC\200\035\201\200\000\001\000\002\000\002\000\000ÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­Þ"}},
     M_databuf = "\000\030\000\003\000þÿÿ\000\000\000\000\000\000\000\000¯\000\000\000\000\000\000\000\001\000\000\000ëé\000\000\000\000\000\000ÞÀ­Þ@8\214\005\000þÿÿE\000ì\000\223Ò\000\000E\000¯\000\223Ò\000\0007\004(\002P\226Aº\201»³WE\000\000¯_-\000\000\177\001\034G\n\233\a\002¬\031\001$\003\003¼g\000\000\000\000E\000\000\223\215:\000\000>\0210F¬\031\001$\n\233\a\002\0005äv\000\177\vC\200\035\201\200\000\001\000\002\000\002\000\000ÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­ÞÞÀ­Þ"...}}
(kgdb)

### kgdb.out2

- -- 
The beginning is the most important part of the work.
 				-Plato
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.18 (FreeBSD)

iD8DBQFPuo3vSPOsGF+KA+MRAu+AAKDGT0lDqaIcYO4Q6Lx37oUX64GeCgCffGhf
AtfXrgD94GTXHsX7roaKfAI=
=wEqQ
-----END PGP SIGNATURE-----


More information about the freebsd-pf mailing list