On Tue, Jan 08, 2002 at 11:40:54AM +0200, Sami Ponkanen wrote:
> I posted this yesterday to netfilter-devel and linux networking lists, but I
> was instructed that this list might suit better.
Well, from my perspective it's not sure.
> As I wrote earlier on netfilter list and more recently on linux networking
> list, there is a bug that results in a kernel oops when using DNAT or
> REDIRECT rule in the OUTPUT chain on a host with SLIP interfaces.
[...]
> I've traced the problem and it seems that the problem is following:
>
> A buffer for the packet is reserved in ip_build_xmit()
> (net/ipv4/ip_output.c:627) and the correct size for the buffer is calculated
> on line 667:
>
> int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
>
> Now here (I think, correct me if I'm wrong) the hard_header_len is just 1
> byte, the SLIP header byte.
>
> Later on the control goes through nf_hook_slow() (net/core/netfilter.c:445)
> where the packet is put on another output device (skb->dev changes). The
> new device has a different hard_header_len, but skb has only space for the
> 1-byte SLIP header! Am I on the right tracks here?
>
> Ok, again few steps forward and the control reaches neigh_resolve_output()
> (net/core/neighbour.c:950). Here the function dev->hard_header() is called
> and consequently ether_header() (net/ethernet/eth.c:75) is called (why?).
> Right in the beginning of the function the call to skb_push(skb, ETH_HLEN)
> results in skb_under_panic() and BUG() and consequently the system crashes.
mh. I'm not sure why we append an ethernet header, but in any case I think
netfilter is expected to do some more work.
So if we have a NAT rule in the OUTPUT chain, and we call route_me_harder()
from ip_nat_local_fn() we need to check if the hh_len of the output device
has changed. If it has, we need to check if skb has enough headroom and
potentially re-allocate the skb headroom.
Question to the networking gurus:
Is it true that the core networking code expects the skb to have enough
headroom for the hardware header at the time we return from the netfilter
NF_IP_LOCAL_OUT hook?
> A quick fix is to reserve few extra bytes in ip_build_xmit(). I tried
> changing line 676 in ip_output.c from this:
> int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
>
> into this:
> int hh_len = (rt->u.dst.dev->hard_header_len + 31)&~15;
>
> and voila, no more oopses. Well, this is definitely not the correct way to
> fix the problem, but it works for now.
sure. As stated above, I think we need to re-allocate headroom inside the
netfilter hook.
> Now, a few questions came to my mind while debugging the problem. Firstly,
> why do you put an ethernet header on a packet that is sent via the loopback
> device?
no idea. But as loopback is a physical device, it should have at least some
information about which l3 protocol the packet is... and using ethernet
seems convenient.
> Regards,
> Sami Pönkänen
--
Live long and prosper
- Harald Welte / laforge@xxxxxxxxxxxx http://www.gnumonks.org/
============================================================================
GCS/E/IT d- s-: a-- C+++ UL++++$ P+++ L++++$ E--- W- N++ o? K- w--- O- M-
V-- PS+ PE-- Y+ PGP++ t++ 5-- !X !R tv-- b+++ DI? !D G+ e* h+ r% y+(*)
|