Subject: kern/29287: trap in fr_stlookup(): dangerous assumptions with mbuf chains
To: None <email@example.com, firstname.lastname@example.org,>
From: None <email@example.com>
Date: 02/08/2005 13:43:01
>Synopsis: trap in fr_stlookup(): dangerous assumptions with mbuf chains
>Arrival-Date: Tue Feb 08 13:43:00 +0000 2005
>Originator: Quentin Garnier
>Release: NetBSD 2.0_STABLE
System: NetBSD compaq.us.eve 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
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
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.