Panic in ebtables-5 with 2.4.25 with ip_conntrack and vlan

Adam Osuchowski <adwol-QJnc/[email protected]>
Newsgroups gmane.linux.network.bridge.ebtables.devel
Organization Computer Centre of The Silesian University of Technology
Message-ID <[email protected]>
Hello,

there is small problem with ebtables 5 on 2.4.24 & 2.4.25 kernels. When
fragmented IP packet embedded in tagged vlan frame traverses the kernel with
ip_conntrack enabled a panic occures due to memory underflow. The
skb_reserve() function used in ip_fragment() function:

    skb_reserve(skb2, (dev->hard_header_len+15)&~15);

doesn't reserve enough space to handle this frame correctly. The initial
reserved 14 octets for ethernet header between skb->head and skb->data are not
enough to carry tagged ethernet header which length is 18 octets. Since we
have actually reserved 16 octets (aligning) the missed difference is only 2
octets long. Later, nf_bridge_maybe_copy_header() function assumes that there
is 18 octets free space and copies original vlan ethernet header from private
field and skb->data pointer is moving back by 4 octets:

    memcpy(skb->data - 18, skb->nf_bridge->data, 18);
    skb_push(skb, 4);

Next, in br_dev_queue_push_xmit() function tries to move back this pointer by
another 14 octets (ETH_HLEN). In result skb_push() panics.

The following patch resolve this problem but maybe there is better way to fix
it.

Regards,
Adam Osuchowski
Tomasz Dubinski


--- linux-2.4.25/net/ipv4/ip_output.c.orig	2003-11-28 19:26:21.000000000 +0100
+++ linux-2.4.25/net/ipv4/ip_output.c	2004-02-20 12:12:56.000000000 +0100
@@ -792,10 +792,12 @@
 	 */
 
 	while(left > 0)	{
+	  	int vlan_pad = (skb->nf_bridge && (*(unsigned short *)&(skb->nf_bridge->data[3]) == __constant_htons(ETH_P_8021Q))) ? 4 : 0;
+
 		len = left;
 		/* IF: it doesn't fit, use 'mtu' - the data space left */
-		if (len > mtu)
-			len = mtu;
+		if (len > mtu - vlan_pad)
+			len = mtu - vlan_pad;
 		/* IF: we are not sending upto and including the packet end
 		   then align the next start on an eight byte boundary */
 		if (len < left)	{
@@ -805,7 +807,7 @@
 		 *	Allocate buffer.
 		 */
 
-		if ((skb2 = alloc_skb(len+hlen+dev->hard_header_len+15,GFP_ATOMIC)) == NULL) {
+		if ((skb2 = alloc_skb(len+hlen+dev->hard_header_len+15 + vlan_pad, GFP_ATOMIC)) == NULL) {
 			NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n"));
 			err = -ENOMEM;
 			goto fail;
@@ -817,7 +819,7 @@
 
 		skb2->pkt_type = skb->pkt_type;
 		skb2->priority = skb->priority;
-		skb_reserve(skb2, (dev->hard_header_len+15)&~15);
+		skb_reserve(skb2, (dev->hard_header_len+15+vlan_pad)&~15);
 		skb_put(skb2, len + hlen);
 		skb2->nh.raw = skb2->data;
 		skb2->h.raw = skb2->data + hlen;

-- 
##  Adam Osuchowski   adwol-QJnc/[email protected], [email protected]
##  Silesian University of Technology, Computer Centre   Gliwice, Poland


-------------------------------------------------------
SF.Net is sponsored by: Speed Start Your Linux Apps Now.
Build and deploy apps & Web services for Linux with
a free DVD software kit from IBM. Click Now!
http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.