[PATCH v2 11/12] 8021q: Fix data race when publishing vlan net_device pointers
From: Jinjie Ruan
Date: Mon Aug 31 2026 - 22:55:03 EST
A plain C read and assignment of the net_device pointer
in the vlan_devices_arrays leaf entries lack proper atomicity
and ordering barriers. A concurrent lockless reader on the packet
receive fast-path could observe a torn or partially initialized
net_device pointer, leading to a potential out-of-bounds read or kernel
panic.
The data race occurs between the netlink/ioctl configuration paths
(holding the per-netns rtnl_nets_lock or RTNL lock) and the softirq
receive fast-path (holding rcu_read_lock()):
CPU 0 (Writer, rtnl_nets_lock/RTNL) CPU 1 (Reader, rcu_read_lock())
----------------------------------- -------------------------------
rtnetlink_rcv_msg()
// RTM_NEWLINK handler with RTNL_FLAG_DOIT_PERNET
rtnl_newlink()
ops->newlink() == vlan_newlink()
OR
vlan_ioctl_handler()
[ADD_VLAN_CMD] -> register_vlan_device()
register_vlan_dev()
vlan_group_set_device()
netif_receive_skb_core()
vlan_do_receive()
vlan_find_dev()
__vlan_group_get_device()
// Speculative / torn read
[Loads bad net_device *]
[Plain C store]
array[vlan_id] = dev;
// Dereferences bad pointer
// during device status check
vlan_dev->flags (PANIC!)
Fix this by using rcu_assign_pointer() in vlan_group_set_device()
and rcu_dereference_raw() in __vlan_group_get_device() to enforce
proper ordering and memory atomicity for the leaf entry traversal.
Cc: stable@xxxxxxxxxxxxxxx
Cc: "David S. Miller" <davem@xxxxxxxxxxxxx>
Cc: Eric Dumazet <edumazet@xxxxxxxxxx>
Cc: Jakub Kicinski <kuba@xxxxxxxxxx>
Cc: Paolo Abeni <pabeni@xxxxxxxxxx>
Cc: Simon Horman <horms@xxxxxxxxxx>
Cc: Stanislav Fomichev <sdf@xxxxxxxxxxx>
Cc: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx>
Cc: Nicolai Buchwitz <nb@xxxxxxxxxxx>
Cc: Dan Aloni <da-x@xxxxxxxxxxxxx>
Cc: Jeff Garzik <jeff@xxxxxxxxxx>
Fixes: 5c15bdec5c38 ("[VLAN]: Avoid a 4-order allocation.")
Link: https://sashiko.dev/#/patchset/20260825095422.3166067-1-ruanjinjie%40huawei.com
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
net/8021q/vlan.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index c41caaf94095..8030d616cb16 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -62,7 +62,7 @@ static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
/* paired with smp_wmb() in vlan_group_prealloc_vid() */
smp_rmb();
- return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
+ return array ? rcu_dereference_raw(array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN]) : NULL;
}
static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
@@ -88,7 +88,7 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
return;
array = vg->vlan_devices_arrays[pidx]
[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
- array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
+ rcu_assign_pointer(array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN], dev);
}
/* Must be invoked with rcu_read_lock or with RTNL. */
--
2.34.1