kern/85258: changing promisc mode on nic can lead to kernel panic

Pawel Malachowski pawmal-posting at freebsd.lublin.pl
Mon Aug 29 16:47:14 GMT 2005


On Fri, Aug 26, 2005 at 06:40:22PM +0000, Pawel Malachowski wrote:

>  To sum up, factors are:
>  . dummynet configured for outgoing packets seems to be needed;
>  . frequent changes of fxp flags, one can use link0 (setting promisc
>    is not needed at all);
>  . kern.polling.enable=1.

After todays testing I can say that:
. switching from polled fxp(4) to polled rl(4) fixes the problem
. ifconfig fxpX -polling fixes the problem
. can't reproduce problem od 4.10, this is 5.x specific

I would say fxp_ioctl() in case of SIOCSIFFLAGS is not safe on 5.x when
fxp device works in polling mode and dummynet makes easier to expose the
problem.

HTH.

>  I've prepared static kernel for debugging, much better backtrace below. :)
>  
>  Test setup:
>  ipfw pipe 100 config bw 512kbit/s queue 20KB mask src-ip 0xffffffff
>  ipfw add 100 pipe 100 ip from any to any out xmit wan0
>  
>  (wan0 is renamed fxp0)
>  
>  while [ 1 ]
>  do
>   ifconfig $1 link0
>   sleep 1
>   ifconfig $1 -link0
>   sleep 1
>  done
>  
>  And ping -f from another box to speed things up. ;)
>  
>  Full reproducable for me within 10-20 minutes.
>  
>  (kgdb) bt
>  #0  doadump () at pcpu.h:159
>  #1  0xc060c948 in boot (howto=260) at /usr/src/sys/kern/kern_shutdown.c:410
>  #2  0xc060cbc6 in panic (fmt=0xc081e7fd "m_copym, offset > size of mbuf chain") at /usr/src/sys/kern/kern_shutdown.c:566
>  #3  0xc063e500 in m_copym (m=0x0, off0=16380, len=5124, wait=1) at /usr/src/sys/kern/uipc_mbuf.c:385
>  #4  0xc0697780 in ip_fragment (ip=0xc13fa820, m_frag=0xc7aafc44, mtu=-1051870208, if_hwassist_flags=0, sw_csum=1)
>      at /usr/src/sys/netinet/ip_output.c:974
>  #5  0xc0697405 in ip_output (m=0xc13ef700, opt=0xc13fa820, ro=0xc7aafc10, flags=0, imo=0x0, inp=0x0)
>      at /usr/src/sys/netinet/ip_output.c:798
>  #6  0xc068b731 in transmit_event (pipe=0xc16e3d00) at /usr/src/sys/netinet/ip_dummynet.c:454
>  #7  0xc068bab4 in ready_event (q=0xc172e280) at /usr/src/sys/netinet/ip_dummynet.c:624
>  #8  0xc068c04b in dummynet (unused=0x0) at /usr/src/sys/netinet/ip_dummynet.c:779
>  #9  0xc0617b12 in softclock (dummy=0x0) at /usr/src/sys/kern/kern_timeout.c:279
>  #10 0xc05fb4b8 in ithread_loop (arg=0xc12b9500) at /usr/src/sys/kern/kern_intr.c:547
>  #11 0xc05fa92c in fork_exit (callout=0xc05fb394 <ithread_loop>, arg=0xc12b9500, frame=0xc7aafd48)
>      at /usr/src/sys/kern/kern_fork.c:791
>  #12 0xc07a0a4c in fork_trampoline () at /usr/src/sys/i386/i386/exception.s:209
>  (kgdb) up 3
>  #3  0xc063e500 in m_copym (m=0x0, off0=16380, len=5124, wait=1) at /usr/src/sys/kern/uipc_mbuf.c:385
>  385                     KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain"));
>  (kgdb) l
>  380             KASSERT(len >= 0, ("m_copym, negative len %d", len));
>  381             MBUF_CHECKSLEEP(wait);
>  382             if (off == 0 && m->m_flags & M_PKTHDR)
>  383                     copyhdr = 1;
>  384             while (off > 0) {
>  385                     KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain"));
>  386                     if (off < m->m_len)
>  387                             break;
>  388                     off -= m->m_len;
>  389                     m = m->m_next;
>  (kgdb) up
>  #4  0xc0697780 in ip_fragment (ip=0xc13fa820, m_frag=0xc7aafc44, mtu=-1051870208, if_hwassist_flags=0, sw_csum=1)
>      at /usr/src/sys/netinet/ip_output.c:974
>  974                     m->m_next = m_copy(m0, off, len);
>  (kgdb) l
>  969                             len = ip->ip_len - off;
>  970                             m->m_flags |= M_LASTFRAG;
>  971                     } else
>  972                             mhip->ip_off |= IP_MF;
>  973                     mhip->ip_len = htons((u_short)(len + mhlen));
>  974                     m->m_next = m_copy(m0, off, len);
>  975                     if (m->m_next == NULL) {        /* copy failed */
>  976                             m_free(m);
>  977                             error = ENOBUFS;        /* ??? */
>  978                             ipstat.ips_odropped++;
>  (kgdb) up
>  #5  0xc0697405 in ip_output (m=0xc13ef700, opt=0xc13fa820, ro=0xc7aafc10, flags=0, imo=0x0, inp=0x0)
>      at /usr/src/sys/netinet/ip_output.c:798
>  798             error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist, sw_csum);
>  (kgdb) l
>  793              * Too large for interface; fragment if possible. If successful,
>  794              * on return, m will point to a list of packets to be sent.
>  795              */
>  796     /*if (ifp->if_mtu) {
>  797     }*/
>  798             error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist, sw_csum);
>  799             if (error)
>  800                     goto bad;
>  801             for (; m; m = m0) {
>  802                     m0 = m->m_nextpkt;


-- 
Paweł Małachowski


More information about the freebsd-bugs mailing list