When experimental vhost-net zero-copy TX is used with an IFF_NAPI_FRAGS TAP backend, tun_get_user() receives msg_control, selects zerocopy, and limits copylen to the linear prefix. The NAPI frags path subsequently disables zerocopy after allocating the skb and copies the complete frame instead. tun_napi_alloc_frags() derives the linear length from the first iterator segment, so a segment larger than copylen makes skb->data_len underflow. Pulling the Ethernet header then triggers BUG() because skb->len is smaller than skb->data_len. Disable zerocopy before calculating the allocation length so this path allocates and copies the complete iterator. Fixes: 90e33d459407 ("tun: enable napi_gro_frags() for TUN/TAP driver") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Harshit Mogalapalli --- drivers/net/tun.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 5a302709a68a..1124b8b33664 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1848,6 +1848,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, zerocopy = true; } + /* The NAPI frags path copies the complete iterator. */ + if (frags) + zerocopy = false; + if (!frags && tun_can_build_skb(tun, tfile, len, noblock, zerocopy)) { /* For the packet that is not easy to be processed * (e.g gso or jumbo packet), we will do it at after @@ -1868,11 +1872,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, if (frags) { mutex_lock(&tfile->napi_mutex); skb = tun_napi_alloc_frags(tfile, copylen, from); - /* tun_napi_alloc_frags() enforces a layout for the skb. - * If zerocopy is enabled, then this layout will be - * overwritten by zerocopy_sg_from_iter(). - */ - zerocopy = false; } else { if (!linear) linear = min_t(size_t, good_linear, copylen); -- 2.52.0