[Saucy] [PATCH] SRU: zerocopy LSO segmenting fixed

Anton Nayshtut anton at swortex.com
Sun Jun 22 08:07:42 UTC 2014


BugLink: https://bugs.launchpad.net/bugs/1328973

[SRU Justification]

[Setup]
 - 2 or more QEMU Guest VMs sharing the the same host
 - the Guests are communicating using virtio-net-pci devices
 - vhost-net is enabled

[Explanation]
If one Guest VM sends GSO packets to another while GRO is disabled for receiver,
so these packets are segmented by net/core.
In this case, if zero-copy is enabled in vhost-net, the GSO packets TX
completion is reported to userspace as before the TX is actually done.
The vhost-net's zero-copy mechanism is enabled by default since v3.8-rc1
(f9611c43).

[Impact]
Incorrect/junk data sent in case the transmitting Guest OS re-uses/frees the TX
buffer immediately upon TX completion.

[Test Case]
Windows 2008R2 Guest VMs running MS HCK Offload LSO test.
NOTE1: GRO is always disabled in this case because it's not supported by Windows
Guest virtio-net-pci drivers.
NOTE2: MS HCK re-uses the GSO (LSO) buffers, so it reproduces the issue every
time.

   skbuff: skb_segment: orphan frags before copying

    skb_segment copies frags around, so we need
    to copy them carefully to avoid accessing
    user memory after reporting completion to userspace
    through a callback.

    skb_segment doesn't normally happen on datapath:
    TSO needs to be disabled - so disabling zero copy
    in this case does not look like a big deal.

    OriginalAuthor: Michael S. Tsirkin <mst at redhat.com>
    Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
    Acked-by: Herbert Xu <herbert at gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem at davemloft.net>

    (cherry picked from commit 1fd819ecb90cc9b822cd84d3056ddba315d3340f)
    CVE-2014-0131
    Signed-off-by: Andy Whitcroft <apw at canonical.com>
    (backported from 0f860fb4f583909ed999df58abf57ff40ec94d6d ubuntu-trusty)
    Signed-off-by: Anton Nayshtut <anton at swortex.com>

---
 net/core/skbuff.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index abcad83..586bca9 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2729,6 +2729,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 	struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
 	unsigned int mss = skb_shinfo(skb)->gso_size;
 	unsigned int doffset = skb->data - skb_mac_header(skb);
+	struct sk_buff *frag_skb = skb;
 	unsigned int offset = doffset;
 	unsigned int tnl_hlen = skb_tnl_header_len(skb);
 	unsigned int headroom;
@@ -2769,6 +2770,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 		if (!hsize && i >= nfrags) {
 			BUG_ON(fskb->len != len);
 
+			frag_skb = fskb;
 			pos += len;
 			nskb = skb_clone(fskb, GFP_ATOMIC);
 			fskb = fskb->next;
@@ -2838,6 +2840,8 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 		skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
 
 		while (pos < offset + len && i < nfrags) {
+			if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
+				goto err;
 			*frag = skb_shinfo(skb)->frags[i];
 			__skb_frag_ref(frag);
 			size = skb_frag_size(frag);
-- 
1.7.9.5





More information about the kernel-team mailing list