Skip to contentSkip to conversation

FAILED: patch "[PATCH] net: tap: set skb->dev before parsing virtio net header in" failed to apply to 6.12-stable tree

PATCH In review [email protected] 3 participants 3 messages Aug 13 – Aug 20

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 3874892dd27d5387aa9a06f58d9060f18f351d24
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026081349-dropout-afoot-d502@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 3874892dd27d5387aa9a06f58d9060f18f351d24 Mon Sep 17 00:00:00 2001
From: Dongli Zhang <[email protected]>
Date: Sun, 2 Aug 2026 15:46:12 -0700
Subject: [PATCH] net: tap: set skb->dev before parsing virtio net header in
tap_get_user_xdp()

The commit 4f61f133f354 ("net: tap: NULL pointer derefence in dev_parse_header_protocol when skb->dev is null") fixed a crash in tap_get_user() by assigning skb->dev before calling tun_vnet_hdr_to_skb(). This is required because virtio_net_hdr_to_skb() may invoke dev_parse_header_protocol(), which dereferences skb->dev. Without the assignment, a NULL pointer dereference can occur.

However, tap_get_user_xdp() still parses the virtio-net header before assigning skb->dev. When the vhost TX path passes an XDP buffer containing a GSO virtio-net header but the protocol is set to zero on purpose, tun_vnet_hdr_to_skb() can reach dev_parse_header_protocol() while skb->dev is still NULL, resulting in a crash.

Fix this by looking up the tap device and assigning skb->dev before calling tun_vnet_hdr_to_skb(), matching the ordering already used in tap_get_user(). Preserve the existing RCU read-side critical section across dev_queue_xmit().

Fixes 924a9bc362a5 ("net: check if protocol extracted by virtio_net_hdr_set_proto is correct")
drivers/net/tap.c +14 -10
index fae115915c8e..5d2d34d24ce8 100644
@@ -1074,10 +1074,21 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
 	skb_reset_mac_header(skb);
 	skb->protocol = eth_hdr(skb)->h_proto;
 
+	rcu_read_lock();
+	tap = rcu_dereference(q->tap);
+	if (!tap) {
+		kfree_skb(skb);
+		rcu_read_unlock();
+		return 0;
+	}
+	skb->dev = tap->dev;
+
 	if (vnet_hdr_len) {
 		err = tun_vnet_hdr_to_skb(q->flags, skb, gso);
-		if (err)
+		if (err) {
+			rcu_read_unlock();
 			goto err_kfree;
+		}
 	}
 
 	/* Move network header to the right position for VLAN tagged packets */
@@ -1085,15 +1096,8 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
 	    vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
 		skb_set_network_header(skb, depth);
 
-	rcu_read_lock();
-	tap = rcu_dereference(q->tap);
-	if (tap) {
-		skb->dev = tap->dev;
-		skb_probe_transport_header(skb);
-		dev_queue_xmit(skb);
-	} else {
-		kfree_skb(skb);
-	}
+	skb_probe_transport_header(skb);
+	dev_queue_xmit(skb);
 	rcu_read_unlock();
 
 	return 0;
maintainer
#1 lore raw

PATCH 1/1 net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()

From: Dongli Zhang <[email protected]>

[ Upstream commit 3874892dd27d5387aa9a06f58d9060f18f351d24 ]

The commit 4f61f133f354 ("net: tap: NULL pointer derefence in dev_parse_header_protocol when skb->dev is null") fixed a crash in tap_get_user() by assigning skb->dev before calling tun_vnet_hdr_to_skb(). This is required because virtio_net_hdr_to_skb() may invoke dev_parse_header_protocol(), which dereferences skb->dev. Without the assignment, a NULL pointer dereference can occur.

However, tap_get_user_xdp() still parses the virtio-net header before assigning skb->dev. When the vhost TX path passes an XDP buffer containing a GSO virtio-net header but the protocol is set to zero on purpose, tun_vnet_hdr_to_skb() can reach dev_parse_header_protocol() while skb->dev is still NULL, resulting in a crash.

Fix this by looking up the tap device and assigning skb->dev before calling tun_vnet_hdr_to_skb(), matching the ordering already used in tap_get_user(). Preserve the existing RCU read-side critical section across dev_queue_xmit().

Fixes 924a9bc362a5 ("net: check if protocol extracted by virtio_net_hdr_set_proto is correct")
---
 drivers/net/tap.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)
drivers/net/tap.c +14 -10
index c460b1f39136a..b3cb7d5a95850 100644
@@ -1199,10 +1199,21 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
 	skb_reset_mac_header(skb);
 	skb->protocol = eth_hdr(skb)->h_proto;
 
+	rcu_read_lock();
+	tap = rcu_dereference(q->tap);
+	if (!tap) {
+		kfree_skb(skb);
+		rcu_read_unlock();
+		return 0;
+	}
+	skb->dev = tap->dev;
+
 	if (vnet_hdr_len) {
 		err = virtio_net_hdr_to_skb(skb, gso, tap_is_little_endian(q));
-		if (err)
+		if (err) {
+			rcu_read_unlock();
 			goto err_kfree;
+		}
 	}
 
 	/* Move network header to the right position for VLAN tagged packets */
@@ -1210,15 +1221,8 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
 	    vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
 		skb_set_network_header(skb, depth);
 
-	rcu_read_lock();
-	tap = rcu_dereference(q->tap);
-	if (tap) {
-		skb->dev = tap->dev;
-		skb_probe_transport_header(skb);
-		dev_queue_xmit(skb);
-	} else {
-		kfree_skb(skb);
-	}
+	skb_probe_transport_header(skb);
+	dev_queue_xmit(skb);
 	rcu_read_unlock();
 
 	return 0;
Signature · 1 line
2.53.0
#2 lore raw

Re: [PATCH 6.12.y] net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()

Hey Sasha,

Can you post this backport for the remaining stable too? It seems you missed the other FAILED emails.

git am works without any conflict.

Thanks,
Siddh