Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2677

kernel-2.6.18-238.el5.src.rpm

From: Herbert Xu <herbert.xu@redhat.com>
Date: Fri, 13 Feb 2009 16:23:46 +0800
Subject: [net] handle non-linear packets in skb_checksum_setup
Message-id: 20090213082346.GA25550@gondor.apana.org.au
O-Subject: [RHEL5.4 PATCH] net: Handle non-linear packets in skb_checksum_setup
Bugzilla: 477012
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: David Miller <davem@redhat.com>
RH-Acked-by: Thomas Graf <tgraf@redhat.com>

Hi:

RHEL5.4 BZ #477012

This patch fixes a bug that causes certain packets from guests
to be dropped by the host.  The bug is triggered when the guest
gives us a packet with a head that is too small.  In this particular
instance, it was caused by a guest with slab debugging enabled,
which results in skb->data crossing a page boundary.

I'm surprised that we still have slab debugging enabled as it
causes all sorts of untested code paths to be run.

In any case, this patch fixes this particular problem.  Note that
this function is Xen-specific and not part of the upstream kernel.

commit 746f017bfef6154649fef2b6912560aaad78b184
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date:   Fri Feb 13 16:12:03 2009 +0800

    net: Handle non-linear packets in skb_checksum_setup

    Some domUs may send us non-linear packets unwittingly, e.g., because
    they have slab debugging enabled which causes packets with skb->data
    that crosses a page boundary to be generated.

    We should handle these cases instead of dropping these packets.

    In fact, dropping these packets can result in hanging TCP connections
    since TCP will continue to retransmit the same skb that crosses the
    page boundary until the connection dies.

    Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/net/core/dev.c b/net/core/dev.c
index c9a36a4..56829cc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1403,9 +1403,11 @@ inline int skb_checksum_setup(struct sk_buff *skb)
 	if (skb->proto_csum_blank) {
 		if (skb->protocol != htons(ETH_P_IP))
 			goto out;
-		skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
-		if (skb->h.raw >= skb->tail)
+		if (skb->data < skb->nh.raw + sizeof(*skb->nh.iph) &&
+		    !pskb_may_pull(skb, skb->nh.raw + sizeof(*skb->nh.iph) -
+					skb->data))
 			goto out;
+		skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
 		switch (skb->nh.iph->protocol) {
 		case IPPROTO_TCP:
 			skb->csum = offsetof(struct tcphdr, check);
@@ -1420,7 +1422,8 @@ inline int skb_checksum_setup(struct sk_buff *skb)
 				       " %d packet", skb->nh.iph->protocol);
 			goto out;
 		}
-		if ((skb->h.raw + skb->csum + 2) > skb->tail)
+		if (skb->data < skb->h.raw + skb->csum + 2 &&
+		    !pskb_may_pull(skb, skb->h.raw + skb->csum + 2 - skb->data))
 			goto out;
 		skb->ip_summed = CHECKSUM_HW;
 		skb->proto_csum_blank = 0;