diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2014-11-03 04:30:14 +0800 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2017-03-16 02:27:24 +0000 |
commit | 5e93a95d21c6e18db8bc6248367b325996586ad2 (patch) | |
tree | 69bbf527f8189a2e7fe16f841c5aa7b991ae572e /drivers/net | |
parent | f8efa7a216b2c666727cc395b670575efeb33ef3 (diff) | |
download | linux-stable-5e93a95d21c6e18db8bc6248367b325996586ad2.tar.gz linux-stable-5e93a95d21c6e18db8bc6248367b325996586ad2.tar.bz2 linux-stable-5e93a95d21c6e18db8bc6248367b325996586ad2.zip |
tun: Fix TUN_PKT_STRIP setting
commit 2eb783c43e7cf807a45899c10ed556b6dc116625 upstream.
We set the flag TUN_PKT_STRIP if the user buffer provided is too
small to contain the entire packet plus meta-data. However, this
has been broken ever since we added GSO meta-data. VLAN acceleration
also has the same problem.
This patch fixes this by taking both into account when setting the
TUN_PKT_STRIP flag.
The fact that this has been broken for six years without anyone
realising means that nobody actually uses this flag.
Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/tun.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 343a71ad865b..7ab19ac937b7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1227,15 +1227,19 @@ static ssize_t tun_put_user(struct tun_struct *tun, ssize_t total = 0; int vlan_offset = 0, copied; int vlan_hlen = 0; + int vnet_hdr_sz = 0; if (vlan_tx_tag_present(skb)) vlan_hlen = VLAN_HLEN; + if (tun->flags & TUN_VNET_HDR) + vnet_hdr_sz = tun->vnet_hdr_sz; + if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) < 0) return -EINVAL; - if (len < skb->len) { + if (len < skb->len + vlan_hlen + vnet_hdr_sz) { /* Packet will be striped */ pi.flags |= TUN_PKT_STRIP; } @@ -1245,9 +1249,9 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += sizeof(pi); } - if (tun->flags & TUN_VNET_HDR) { + if (vnet_hdr_sz) { struct virtio_net_hdr gso = { 0 }; /* no info leak */ - if ((len -= tun->vnet_hdr_sz) < 0) + if ((len -= vnet_hdr_sz) < 0) return -EINVAL; if (skb_is_gso(skb)) { @@ -1291,7 +1295,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, sizeof(gso)))) return -EFAULT; - total += tun->vnet_hdr_sz; + total += vnet_hdr_sz; } copied = total; |