[ previous ] [ next ] [ threads ]
 From:  Manuel Kasper <mk at neon1 dot net>
 To:  Chris Boot <bootc at bootc dot net>
 Cc:  m0n0wall at lists dot m0n0 dot ch, "Christopher M. Iarocci" <iarocci at eastendsc dot com>
 Subject:  Re: [m0n0wall] Beta 1.3b6 released
 Date:  Sun, 23 Dec 2007 17:34:26 +0100
On 23.12.2007, at 12:03, Chris Boot wrote:

> I've just upgraded to 1.3b6 and my IPsec VPN appears to crash  
> m0n0wall:
> ...
> Fatal trap 12: page fault while in kernel mode
> fault virtual address   = 0x4
> fault code              = supervisor write, page not present

Thanks for the report - I've been able to reproduce this issue. It's  
a bug in FreeBSD 6.2 (i.e. not m0n0wall-specific), as I've also been  
able to provoke this kind of crash on a stock FreeBSD 6.2 machine. It  
is encountered in m0n0wall 1.3b6 if all of the following conditions  
are true:

- at least one IPsec tunnel is configured

- the traffic shaper is enabled

- there is a traffic shaper rule on the WAN interface (or on  
whichever interface the tunnel is terminated) that matches *incoming*  
decapsulated packets

Then, as soon as one such packet is received, the kernel tries to  
write to an invalid memory location and panics. This bug has only  
surfaced now that m0n0wall supports filtering of decapsulated IPsec  
packets via the enc0 interface.

I've found the problem in the kernel (technical details: see below)  
and created a fixed version, 1.3b7-pre, which you can download here:


Please let me know if this fixes the problem for you.



Technical details:

I've done some kernel debugging, and it appears that the problem is  
related to calling ipsec_filter() in sys/net/if_enc.c, which passes  
packets through the pfil hooks. When a packet is passed to dummynet,  
it gets "consumed" by ipfw and the pointer to the mbuf that was  
passed in gets set to NULL. ipsec_filter() detects this and simply  
returns the error code that it got from pfil_run_hooks(), which is 0  
even if the packet has been consumed. However, in the three functions  
where ipsec_filter() is called (in sys/netipsec/ 
{ipsec_input.c,ipsec_output.c,xform_ipip.c}), only a non-zero return  
value from ipsec_filter() causes processing to stop.

Therefore, when a packet was consumed by dummynet, the ipsec_filter()  
callers in the three mentioned files continue processing with the now  
NULL mbuf, which of course then leads to a kernel panic.

I've also noticed that ipfw doesn't match inbound packets on enc0,  
but on the interface where the encapsulated ESP packet came in  
instead, which is hardly surprising, as ipfw_check_in() in netinet/ 
ip_fw_pfil.c ignores its "ifp" argument and if_enc doesn't replace  
the ifp in the mbuf with the one for enc0. It works for outbound  
packets on enc0 as ipfw_check_out() honors the ifp argument. However,  
this is irrelevant for m0n0wall at present, since there's no GUI  
support for adding traffic shaper rules on enc0 (only filter rules,  
and ipfilter works fine both inbound and outbound on enc0). The fact  
needs to be considered though that incoming decapsulated IPsec  
packets can also match shaper rules on the interface where the  
corresponding ESP packet came in. Outbound to-be-encapsulated packets  
won't match though.

I guess I'll file a FreeBSD PR about this soon.