Subject: kern/29287: trap in fr_stlookup(): dangerous assumptions with mbuf chains
To: None <,,>
From: None <>
List: netbsd-bugs
Date: 02/08/2005 13:43:01
>Number:         29287
>Category:       kern
>Synopsis:       trap in fr_stlookup(): dangerous assumptions with mbuf chains
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Feb 08 13:43:00 +0000 2005
>Originator:     Quentin Garnier
>Release:        NetBSD 2.0_STABLE
System: NetBSD 2.0_STABLE NetBSD 2.0_STABLE (COMPAQ.US) #1: Tue Jan 4 09:48:03 PST 2005 qgarnier@yerbabuena:/home/qgarnier/netbsd-2/obj/home/qgarnier/netbsd-2/src/sys/arch/i386/compile/COMPAQ.US.R i386
Architecture: i386
Machine: i386
	I get a trap in fr_stlookup() about every day.  Until today I had no
	time to look at it closely, but now I have tracked the issue down to
	the way mbuf chains are passed to the IPFilter code.  It is not a bug
	in IPFilter itself.

	The two panics I could deeply analyze followed the same trace:
		o pptpctrl (from net/poptop) generates GRE packets from what
		  it receives from the matching ppp interface.
		o it doesn't write an IP header, so rip_output() generates
		o doing so, it calls M_PREPEND on the mbuf chain to get space
		  for an IP header.
		o *sometimes* (obviously not always or I'd have noticed that
		  much earlier), the chain will get prepended with a mbuf of
		  size 20 whose data pointer gets "aligned" on a page.  What I
		  mean by that is the mbuf has space for 20 bytes, and then no
		  more, as it reach a page boundary.
		o rip_output transmits the mbuf chain to ip_output, and then
		  through the pfil hooks it reaches fr_check_wrapper.
		o fr_check_wrapper doens't check any length and passes the
		  data from the first mbuf of the chain to fr_check.
		o it reaches fr_stlookup, which has code for IPPROTO_GRE which
		  tries to access data in the GRE header, which it *assumes*
		  is right after the IP header.
		o kernel gets a page fault and my job security weakens.

	I think the trigger of the fault is the way the prepended packet is
	aligned.  If it is far enough from a page boundary, the code in
	fr_stlookup() will get garbage, but work, for some definition of it.
	I don't know a way to reproduce it easily right now, but I will do some
	tests later.

	However, it does happen about every day in my setup.
	I'll try a gross hack for my server, doing a m_pullup(m, 36) in
	rip_output, but of course the right way to do that is to inform IPF of
	the size of the buffer it is working on.  Easier said than done, as
	the kernel would also have to provide a way for IPFilter to get the
	following chunks of data.