FAILED: patch "[PATCH] vlan: fix skb_under_panic and races when toggling HW VLAN" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe 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 447cbe95ebb95392b5d8f6a01c0556826919ce23
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026083118-ranged-peddling-d8e5@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 447cbe95ebb95392b5d8f6a01c0556826919ce23 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <[email protected]>
Date: Tue, 11 Aug 2026 08:52:46 +0000
Subject: [PATCH] vlan: fix skb_under_panic and races when toggling HW VLAN
offload
Toggling hardware VLAN TX offload (NETIF_F_HW_VLAN_CTAG_TX or NETIF_F_HW_VLAN_STAG_TX) on a lower device invokes vlan_transfer_features(), which dynamically changed vlandev->hard_header_len.
This causes two issues:
1. Lockless TX paths (e.g. packet_snd in af_packet.c, ip6_finish_output2) read dev->hard_header_len without holding RTNL lock. Mutating hard_header_len dynamically under RTNL creates a data race where upper layers reserve insufficient headroom based on a stale hard_header_len, resulting in skb_under_panic when vlan_dev_hard_header() is called.
2. In addition, vlan_transfer_features() updated hard_header_len without updating header_ops, causing a mismatch between allocated headroom and header creation.
Always setting dev->hard_header_len = real_dev->hard_header_len and dev->needed_headroom = real_dev->needed_headroom + VLAN_HLEN unconditionally ensures:
- dev->hard_header_len remains 100% static and immutable at real_dev->hard_header_len, eliminating all dynamic runtime updates and data races on hard_header_len.
- Upper layers allocating skbs via LL_RESERVED_SPACE() will always reserve sufficient headroom for software VLAN tag insertion (real_dev->hard_header_len + real_dev->needed_headroom + VLAN_HLEN).
- vlandev inherits real_dev->needed_tailroom so underlying trailer/padding/ICV requirements are honored.
- AF_PACKET SOCK_RAW network header offsets remain correctly aligned at real_dev->hard_header_len.
- vlan_header_ops is used unconditionally.
Note to stable teams: Make sure to backport these commits:
e16e960d55a4 ("ipvlan: inherit needed_headroom and needed_tailroom from phy_dev") cef51860becd ("macvlan: inherit needed_headroom and needed_tailroom from lowerdev")
net/8021q/vlan_dev.c +7 -32
@@ -502,26 +502,6 @@ static const struct header_ops vlan_header_ops = { .parse_protocol = vlan_parse_protocol, }; -static int vlan_passthru_hard_header (struct sk_buff *skb,struct net_device *dev, -unsigned short type, -const void *daddr,const void *saddr, -unsigned int len) -{ -struct vlan_dev_priv *vlan =vlan_dev_priv (dev); -struct net_device *real_dev = vlan->real_dev; - -if (saddr ==NULL ) - saddr = dev->dev_addr; - -return dev_hard_header (skb, real_dev, type, daddr, saddr, len); -} - -static const struct header_ops vlan_passthru_header_ops = { - .create = vlan_passthru_hard_header, - .parse = eth_header_parse, - .parse_protocol = vlan_parse_protocol, -}; -static const struct device_type vlan_type = { .name ="vlan" , };
@@ -580,14 +560,10 @@ static int vlan_dev_init(struct net_device *dev) dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;#endif - dev->needed_headroom = real_dev->needed_headroom; -if (vlan_hw_offload_capable (real_dev->features, vlan->vlan_proto)) { - dev->header_ops = &vlan_passthru_header_ops; - dev->hard_header_len = real_dev->hard_header_len; - }else { - dev->header_ops = &vlan_header_ops; - dev->hard_header_len = real_dev->hard_header_len +VLAN_HLEN ; - } + dev->needed_headroom = real_dev->needed_headroom +VLAN_HLEN ; + dev->needed_tailroom = real_dev->needed_tailroom; + dev->header_ops = &vlan_header_ops; + dev->hard_header_len = real_dev->hard_header_len; dev->netdev_ops = &vlan_netdev_ops;
@@ -1029,10 +1005,9 @@ static void vlan_transfer_features(struct net_device *dev,netif_inherit_tso_max (vlandev, dev); -if (vlan_hw_offload_capable (dev->features, vlan->vlan_proto)) - vlandev->hard_header_len = dev->hard_header_len; -else - vlandev->hard_header_len = dev->hard_header_len +VLAN_HLEN ; + vlandev->needed_headroom = dev->needed_headroom +VLAN_HLEN ; + vlandev->needed_tailroom = dev->needed_tailroom; + vlandev->hard_header_len = dev->hard_header_len;#if IS_ENABLED (CONFIG_FCOE ) vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
Sasha Levin
maintainerPATCH 1/1 vlan: fix skb_under_panic and races when toggling HW VLAN offload
From: Eric Dumazet <[email protected]>
[ Upstream commit 447cbe95ebb95392b5d8f6a01c0556826919ce23 ]
Toggling hardware VLAN TX offload (NETIF_F_HW_VLAN_CTAG_TX or NETIF_F_HW_VLAN_STAG_TX) on a lower device invokes vlan_transfer_features(), which dynamically changed vlandev->hard_header_len.
This causes two issues:
1. Lockless TX paths (e.g. packet_snd in af_packet.c, ip6_finish_output2) read dev->hard_header_len without holding RTNL lock. Mutating hard_header_len dynamically under RTNL creates a data race where upper layers reserve insufficient headroom based on a stale hard_header_len, resulting in skb_under_panic when vlan_dev_hard_header() is called.
2. In addition, vlan_transfer_features() updated hard_header_len without updating header_ops, causing a mismatch between allocated headroom and header creation.
Always setting dev->hard_header_len = real_dev->hard_header_len and dev->needed_headroom = real_dev->needed_headroom + VLAN_HLEN unconditionally ensures:
- dev->hard_header_len remains 100% static and immutable at real_dev->hard_header_len, eliminating all dynamic runtime updates and data races on hard_header_len.
- Upper layers allocating skbs via LL_RESERVED_SPACE() will always reserve sufficient headroom for software VLAN tag insertion (real_dev->hard_header_len + real_dev->needed_headroom + VLAN_HLEN).
- vlandev inherits real_dev->needed_tailroom so underlying trailer/padding/ICV requirements are honored.
- AF_PACKET SOCK_RAW network header offsets remain correctly aligned at real_dev->hard_header_len.
- vlan_header_ops is used unconditionally.
Note to stable teams: Make sure to backport these commits:
e16e960d55a4 ("ipvlan: inherit needed_headroom and needed_tailroom from phy_dev") cef51860becd ("macvlan: inherit needed_headroom and needed_tailroom from lowerdev")
--- net/8021q/vlan.c | 7 +++---- net/8021q/vlan_dev.c | 32 ++++---------------------------- 2 files changed, 7 insertions(+), 32 deletions(-)
net/8021q/vlan.c +3 -4
@@ -324,10 +324,9 @@ static void vlan_transfer_features(struct net_device *dev,netif_inherit_tso_max (vlandev, dev); -if (vlan_hw_offload_capable (dev->features, vlan->vlan_proto)) - vlandev->hard_header_len = dev->hard_header_len; -else - vlandev->hard_header_len = dev->hard_header_len +VLAN_HLEN ; + vlandev->needed_headroom = dev->needed_headroom +VLAN_HLEN ; + vlandev->needed_tailroom = dev->needed_tailroom; + vlandev->hard_header_len = dev->hard_header_len;#if IS_ENABLED (CONFIG_FCOE ) vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid;
net/8021q/vlan_dev.c +4 -28
@@ -494,26 +494,6 @@ static const struct header_ops vlan_header_ops = { .parse_protocol = vlan_parse_protocol, }; -static int vlan_passthru_hard_header (struct sk_buff *skb,struct net_device *dev, -unsigned short type, -const void *daddr,const void *saddr, -unsigned int len) -{ -struct vlan_dev_priv *vlan =vlan_dev_priv (dev); -struct net_device *real_dev = vlan->real_dev; - -if (saddr ==NULL ) - saddr = dev->dev_addr; - -return dev_hard_header (skb, real_dev, type, daddr, saddr, len); -} - -static const struct header_ops vlan_passthru_header_ops = { - .create = vlan_passthru_hard_header, - .parse = eth_header_parse, - .parse_protocol = vlan_parse_protocol, -}; -static const struct device_type vlan_type = { .name ="vlan" , };
@@ -572,14 +552,10 @@ static int vlan_dev_init(struct net_device *dev) dev->fcoe_ddp_xid = real_dev->fcoe_ddp_xid;#endif - dev->needed_headroom = real_dev->needed_headroom; -if (vlan_hw_offload_capable (real_dev->features, vlan->vlan_proto)) { - dev->header_ops = &vlan_passthru_header_ops; - dev->hard_header_len = real_dev->hard_header_len; - }else { - dev->header_ops = &vlan_header_ops; - dev->hard_header_len = real_dev->hard_header_len +VLAN_HLEN ; - } + dev->needed_headroom = real_dev->needed_headroom +VLAN_HLEN ; + dev->needed_tailroom = real_dev->needed_tailroom; + dev->header_ops = &vlan_header_ops; + dev->hard_header_len = real_dev->hard_header_len; dev->netdev_ops = &vlan_netdev_ops;
Signature · 1 line
2.53.0