Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S964891AbdCJMXX (ORCPT ); Fri, 10 Mar 2017 07:23:23 -0500 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:45274 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S964870AbdCJMXU (ORCPT ); Fri, 10 Mar 2017 07:23:20 -0500 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "David S. Miller" , "Herbert Xu" Date: Fri, 10 Mar 2017 11:46:23 +0000 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.16 357/370] tun: Fix TUN_PKT_STRIP setting In-Reply-To: X-SA-Exim-Connect-IP: 82.70.136.246 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2100 Lines: 71 3.16.42-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Herbert Xu 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 Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings --- drivers/net/tun.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1227,15 +1227,19 @@ static ssize_t tun_put_user(struct tun_s 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_s 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_s if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, sizeof(gso)))) return -EFAULT; - total += tun->vnet_hdr_sz; + total += vnet_hdr_sz; } copied = total;