panic on ip_input, ip_len byte ordering problem?

kevin brintnall kbrint at rufus.net
Sat Jul 11 04:13:52 UTC 2009


Hi,

Here is my system:

	FreeBSD fw.rufus.net 7.2-RELEASE-p1 FreeBSD 7.2-RELEASE-p1 #1: Wed Jun 10 11:32:28 CDT 2009     root at hamachi.rufus.net:/usr/obj/usr/src/sys/SOEKRIS  i386

I am seeing occasional panics in ip_input when forwarding IP traffic at
low rates (<100pkt/sec).

	Fatal trap 12: page fault while in kernel mode
	cpuid = 0; apic id = 00
	fault virtual address	= 0xc
	fault code		= supervisor read, page not present
	instruction pointer	= 0x20:0xc0872228
	stack pointer	        = 0x28:0xc17f2b20
	frame pointer	        = 0x28:0xc17f2b3c
	code segment		= base 0x0, limit 0xfffff, type 0x1b
				= DPL 0, pres 1, def32 1, gran 1
	processor eflags	= interrupt enabled, resume, IOPL = 0
	current process		= 20 (irq10: sis0 sis1+)
	trap number		= 12
	panic: page fault
	cpuid = 0
	Uptime: 12d10h48m45s
	Physical memory: 115 MB
	Dumping 49 MB: 34 18 2
	Dump complete

The stack trace is as follows:

	#5  0xc0b502cc in trap (frame=0xc17f2ae0) at /usr/src/sys/i386/i386/trap.c:530
	#6  0xc0b342bb in calltrap () at /usr/src/sys/i386/i386/exception.s:159
	#7  0xc0872228 in m_copydata (m=0x0, off=0, len=88, 
	    cp=0xc1aeb6a8 "some garbage") at /usr/src/sys/kern/uipc_mbuf.c:815
	#8  0xc090a728 in ip_forward (m=0xc19f0700, srcrt=0)
	    at /usr/src/sys/netinet/ip_input.c:1307
	#9  0xc090bf0c in ip_input (m=0xc19f0700)
	    at /usr/src/sys/netinet/ip_input.c:609
	#10 0xc08c9fa5 in netisr_dispatch (num=2, m=0xc19f0700)
	    at /usr/src/sys/net/netisr.c:185

m_copydata is walking off the end of the mbuf chain..  It turns out that
the IP header length is incorrect.

Here is the code from frame 8:

	1304	if (mcopy != NULL) {
	1305		mcopy->m_len = min(ip->ip_len, M_TRAILINGSPACE(mcopy));
	1306		mcopy->m_pkthdr.len = mcopy->m_len;
	1307		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
	1308	}

The packet is 116 bytes, which is correctly reflected in the mbuf header.
However, the IP packet length appears to be in network byte order rather
than host byte order.  Note that 29696=ntohs(116).

	(kgdb) p m->m_hdr->mh_len
	$55 = 116
	(kgdb) p mcopy->m_hdr->mh_len
	$56 = 204
	(kgdb) p ip->ip_len
	$57 = 29696		<<-- should be 116!

The rest of the IP header looks correct:

$58 = {ip_hl = 5, ip_v = 4, ip_tos = 16 '\020', ip_len = 29696, ip_id = 38700, 
  ip_off = 64, ip_ttl = 58 ':', ip_p = 6 '\006', ip_sum = 5172, ip_src = {
    s_addr = X}, ip_dst = {s_addr = 1139586513}}

When ip_input is initially called, I think the ip_len must be right..
Otherwise, the "tooshort" block around ip_input.c:383 would stop
processing.

		if (m->m_pkthdr.len < ip->ip_len) {
	tooshort:
			ipstat.ips_tooshort++;
			goto bad;
		}

Any ideas?  My best guess is that there exists a code path in PF somewhere
that is doing an uneven number of ntohs() and htons().

Thanks in advance!

--
 kevin brintnall =~ /kbrint at rufus.net/


More information about the freebsd-net mailing list