netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Fix corruption of skb csum field in pskb_expand_head() of net/core/skbuff.c
@ 2010-07-22 19:12 Andrea Shepard
  2010-07-22 20:28 ` David Miller
  2010-07-23  5:09 ` [PATCH net-next-2.6] net: pskb_expand_head() optimization Eric Dumazet
  0 siblings, 2 replies; 4+ messages in thread
From: Andrea Shepard @ 2010-07-22 19:12 UTC (permalink / raw)
  To: davem; +Cc: linux-kernel, netdev

Make pskb_expand_head() check ip_summed to make sure csum_start is really
csum_start and not csum before adjusting it.

This fixes a bug I encountered using a Sun Quad-Fast Ethernet card and VLANs.
On my configuration, the sunhme driver produces skbs with differing amounts
of headroom on receive depending on the packet size.  See line 2030 of
drivers/net/sunhme.c; packets smaller than RX_COPY_THRESHOLD have 52 bytes
of headroom but packets larger than that cutoff have only 20 bytes.

When these packets reach the VLAN driver, vlan_check_reorder_header()
calls skb_cow(), which, if the packet has less than NET_SKB_PAD (== 32) bytes
of headroom, uses pskb_expand_head() to make more.

Then, pskb_expand_head() needs to adjust a lot of offsets into the skb,
including csum_start.  Since csum_start is a union with csum, if the packet
has a valid csum value this will corrupt it, which was the effect I observed.
The sunhme hardware computes receive checksums, so the skbs would be created
by the driver with ip_summed == CHECKSUM_COMPLETE and a valid csum field, and
then pskb_expand_head() would corrupt the csum field, leading to an "hw csum
error" message later on, for example in icmp_rcv() for pings larger than the
sunhme RX_COPY_THRESHOLD.

On the basis of the comment at the beginning of include/linux/skbuff.h,
I believe that the csum_start skb field is only meaningful if ip_csummed is
CSUM_PARTIAL, so this patch makes pskb_expand_head() adjust it only in that
case to avoid corrupting a valid csum value.

Please see my more in-depth disucssion of tracking down this bug for
more details if you like:

http://puellavulnerata.livejournal.com/112186.html
http://puellavulnerata.livejournal.com/112567.html
http://puellavulnerata.livejournal.com/112891.html
http://puellavulnerata.livejournal.com/113096.html
http://puellavulnerata.livejournal.com/113591.html

I am not subscribed to this list, so please CC me on replies.

Signed-off-by: Andrea Shepard <andrea@persephoneslair.org>

diff -Nau linux-2.6.34.1/net/core/skbuff.c linux-2.6.34.1-skb-csum/net/core/skbuff.c
--- linux-2.6.34.1/net/core/skbuff.c    2010-07-05 11:24:10.000000000 -0700
+++ linux-2.6.34.1-skb-csum/net/core/skbuff.c   2010-07-21 18:42:33.000000000 -0700
@@ -854,7 +854,9 @@
        skb->network_header   += off;
        if (skb_mac_header_was_set(skb))
                skb->mac_header += off;
-       skb->csum_start       += nhead;
+       /* Only adjust this if it actually is csum_start rather than csum */
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               skb->csum_start += nhead;
        skb->cloned   = 0;
        skb->hdr_len  = 0;
        skb->nohdr    = 0;

-- 
Andrea Shepard

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Fix corruption of skb csum field in pskb_expand_head() of net/core/skbuff.c
  2010-07-22 19:12 [PATCH] Fix corruption of skb csum field in pskb_expand_head() of net/core/skbuff.c Andrea Shepard
@ 2010-07-22 20:28 ` David Miller
  2010-07-23  5:09 ` [PATCH net-next-2.6] net: pskb_expand_head() optimization Eric Dumazet
  1 sibling, 0 replies; 4+ messages in thread
From: David Miller @ 2010-07-22 20:28 UTC (permalink / raw)
  To: andrea; +Cc: linux-kernel, netdev

From: Andrea Shepard <andrea@persephoneslair.org>
Date: Thu, 22 Jul 2010 12:12:35 -0700

> Make pskb_expand_head() check ip_summed to make sure csum_start is really
> csum_start and not csum before adjusting it.
...
> Signed-off-by: Andrea Shepard <andrea@persephoneslair.org>

Applied, but your email client corrupted tab characters into spaces so
I had to apply your patch by hand.

There is a similar bug in skb_copy_expand() so I fixed that too.

Thanks again.

--------------------
net: Fix skb_copy_expand() handling of ->csum_start

It should only be adjusted if ip_summed == CHECKSUM_PARTIAL.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/skbuff.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c699159..ce88293 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -932,7 +932,8 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
 	copy_skb_header(n, skb);
 
 	off                  = newheadroom - oldheadroom;
-	n->csum_start       += off;
+	if (n->ip_summed == CHECKSUM_PARTIAL)
+		n->csum_start += off;
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 	n->transport_header += off;
 	n->network_header   += off;
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH net-next-2.6] net: pskb_expand_head() optimization
  2010-07-22 19:12 [PATCH] Fix corruption of skb csum field in pskb_expand_head() of net/core/skbuff.c Andrea Shepard
  2010-07-22 20:28 ` David Miller
@ 2010-07-23  5:09 ` Eric Dumazet
  2010-07-25  4:06   ` David Miller
  1 sibling, 1 reply; 4+ messages in thread
From: Eric Dumazet @ 2010-07-23  5:09 UTC (permalink / raw)
  To: Andrea Shepard, David Miller; +Cc: netdev

Le jeudi 22 juillet 2010 à 12:12 -0700, Andrea Shepard a écrit :
> Make pskb_expand_head() check ip_summed to make sure csum_start is really
> csum_start and not csum before adjusting it.
> 
> This fixes a bug I encountered using a Sun Quad-Fast Ethernet card and VLANs.
> On my configuration, the sunhme driver produces skbs with differing amounts
> of headroom on receive depending on the packet size.  See line 2030 of
> drivers/net/sunhme.c; packets smaller than RX_COPY_THRESHOLD have 52 bytes
> of headroom but packets larger than that cutoff have only 20 bytes.
> 
> When these packets reach the VLAN driver, vlan_check_reorder_header()
> calls skb_cow(), which, if the packet has less than NET_SKB_PAD (== 32) bytes
> of headroom, uses pskb_expand_head() to make more.
> 
> Then, pskb_expand_head() needs to adjust a lot of offsets into the skb,
> including csum_start.  Since csum_start is a union with csum, if the packet
> has a valid csum value this will corrupt it, which was the effect I observed.
> The sunhme hardware computes receive checksums, so the skbs would be created
> by the driver with ip_summed == CHECKSUM_COMPLETE and a valid csum field, and
> then pskb_expand_head() would corrupt the csum field, leading to an "hw csum
> error" message later on, for example in icmp_rcv() for pings larger than the
> sunhme RX_COPY_THRESHOLD.
> 
> On the basis of the comment at the beginning of include/linux/skbuff.h,
> I believe that the csum_start skb field is only meaningful if ip_csummed is
> CSUM_PARTIAL, so this patch makes pskb_expand_head() adjust it only in that
> case to avoid corrupting a valid csum value.
> 
> Please see my more in-depth disucssion of tracking down this bug for
> more details if you like:
> 
> http://puellavulnerata.livejournal.com/112186.html
> http://puellavulnerata.livejournal.com/112567.html
> http://puellavulnerata.livejournal.com/112891.html
> http://puellavulnerata.livejournal.com/113096.html
> http://puellavulnerata.livejournal.com/113591.html
> 
> I am not subscribed to this list, so please CC me on replies.
> 

Excellent Changelog Andrea, thanks !

Reviewing pskb_expand_head(), I see it copy the whole struct
skb_shared_info, even if source contains garbage (uninitialized data).

I wonder why it is not triggering kmemcheck alarms

[PATCH net-next-2.6] net: pskb_expand_head() optimization

Move frags[] at the end of struct skb_shared_info, and make
pskb_expand_head() copy only the used part of it instead of whole array.

This should avoid kmemcheck warnings and speedup pskb_expand_head() as
well, avoiding a lot of cache misses.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 include/linux/skbuff.h |    3 ++-
 net/core/skbuff.c      |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f5aa87e..d89876b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -202,10 +202,11 @@ struct skb_shared_info {
 	 */
 	atomic_t	dataref;
 
-	skb_frag_t	frags[MAX_SKB_FRAGS];
 	/* Intermediate layers must ensure that destructor_arg
 	 * remains valid until skb destructor */
 	void *		destructor_arg;
+	/* must be last field, see pskb_expand_head() */
+	skb_frag_t	frags[MAX_SKB_FRAGS];
 };
 
 /* We divide dataref into two halves.  The higher 16 bits hold references
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 76d33ca..7da58a2 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -817,7 +817,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	memcpy(data + nhead, skb->head, skb->tail - skb->head);
 #endif
 	memcpy(data + size, skb_end_pointer(skb),
-	       sizeof(struct skb_shared_info));
+	       offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
 
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
 		get_page(skb_shinfo(skb)->frags[i].page);



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next-2.6] net: pskb_expand_head() optimization
  2010-07-23  5:09 ` [PATCH net-next-2.6] net: pskb_expand_head() optimization Eric Dumazet
@ 2010-07-25  4:06   ` David Miller
  0 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2010-07-25  4:06 UTC (permalink / raw)
  To: eric.dumazet; +Cc: andrea, netdev

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Fri, 23 Jul 2010 07:09:08 +0200

> [PATCH net-next-2.6] net: pskb_expand_head() optimization
> 
> Move frags[] at the end of struct skb_shared_info, and make
> pskb_expand_head() copy only the used part of it instead of whole array.
> 
> This should avoid kmemcheck warnings and speedup pskb_expand_head() as
> well, avoiding a lot of cache misses.
> 
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>

Maybe it's just that people aren't running kmemcheck when a
pskb_expand_head() triggers, who knows.

Anyways, since we skip the ->frag[] array in skb alloc, etc.,
your patch is of course fine.

Applied, thanks!

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2010-07-25  4:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-22 19:12 [PATCH] Fix corruption of skb csum field in pskb_expand_head() of net/core/skbuff.c Andrea Shepard
2010-07-22 20:28 ` David Miller
2010-07-23  5:09 ` [PATCH net-next-2.6] net: pskb_expand_head() optimization Eric Dumazet
2010-07-25  4:06   ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).