aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2014-11-02 15:30:14 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-03 14:27:06 -0500
commit2eb783c43e7cf807a45899c10ed556b6dc116625 (patch)
tree15b3ea5b89ea7f75965d3ce1c4eba43d69c182c6 /drivers/net/tun.c
parenta8f9bfdf982e2b1fb9f094e4de9ab08c57f3d2fd (diff)
tun: Fix TUN_PKT_STRIP setting
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>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 57e6bf75a632..9dd3746994a4 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1236,15 +1236,19 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1236 ssize_t total = 0; 1236 ssize_t total = 0;
1237 int vlan_offset = 0, copied; 1237 int vlan_offset = 0, copied;
1238 int vlan_hlen = 0; 1238 int vlan_hlen = 0;
1239 int vnet_hdr_sz = 0;
1239 1240
1240 if (vlan_tx_tag_present(skb)) 1241 if (vlan_tx_tag_present(skb))
1241 vlan_hlen = VLAN_HLEN; 1242 vlan_hlen = VLAN_HLEN;
1242 1243
1244 if (tun->flags & TUN_VNET_HDR)
1245 vnet_hdr_sz = tun->vnet_hdr_sz;
1246
1243 if (!(tun->flags & TUN_NO_PI)) { 1247 if (!(tun->flags & TUN_NO_PI)) {
1244 if ((len -= sizeof(pi)) < 0) 1248 if ((len -= sizeof(pi)) < 0)
1245 return -EINVAL; 1249 return -EINVAL;
1246 1250
1247 if (len < skb->len) { 1251 if (len < skb->len + vlan_hlen + vnet_hdr_sz) {
1248 /* Packet will be striped */ 1252 /* Packet will be striped */
1249 pi.flags |= TUN_PKT_STRIP; 1253 pi.flags |= TUN_PKT_STRIP;
1250 } 1254 }
@@ -1254,9 +1258,9 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1254 total += sizeof(pi); 1258 total += sizeof(pi);
1255 } 1259 }
1256 1260
1257 if (tun->flags & TUN_VNET_HDR) { 1261 if (vnet_hdr_sz) {
1258 struct virtio_net_hdr gso = { 0 }; /* no info leak */ 1262 struct virtio_net_hdr gso = { 0 }; /* no info leak */
1259 if ((len -= tun->vnet_hdr_sz) < 0) 1263 if ((len -= vnet_hdr_sz) < 0)
1260 return -EINVAL; 1264 return -EINVAL;
1261 1265
1262 if (skb_is_gso(skb)) { 1266 if (skb_is_gso(skb)) {
@@ -1298,7 +1302,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1298 if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, 1302 if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
1299 sizeof(gso)))) 1303 sizeof(gso))))
1300 return -EFAULT; 1304 return -EFAULT;
1301 total += tun->vnet_hdr_sz; 1305 total += vnet_hdr_sz;
1302 } 1306 }
1303 1307
1304 copied = total; 1308 copied = total;