net/8021q/vlan_dev.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
vlan_dev_change_rx_flags() propagates IFF_PROMISC and IFF_ALLMULTI
changes from a VLAN device to its real device. If the VLAN device has
been moved to another network namespace, a user with CAP_NET_ADMIN in
that namespace can toggle these flags on the VLAN device and change the
promiscuity/allmulti counters on the real device in the original
namespace.
This breaks the namespace boundary for receive-mode state. In a QEMU
reproducer using dummy0 and dummy0.100, dummy0 started with flags 0x83.
After moving dummy0.100 to another netns and running:
ip netns exec testns ip link set dummy0.100 promisc on
ip netns exec testns ip link set dummy0.100 allmulticast on
dummy0 changed to 0x183 and then 0x383. dmesg also showed both
dummy0.100 and dummy0 entering promiscuous/allmulticast mode.
vlan_dev_set_rx_mode() has the same cross-netns issue for unicast and
multicast address sync. Return early in both paths when the VLAN device
and real device are not in the same network namespace. This matches the
existing vlan_hwtstamp_set() namespace check in the same driver.
Fixes: 6c78dcbd47a6 ("[VLAN]: Fix promiscous/allmulti synchronization races")
Cc: stable@vger.kernel.org
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Assisted-by: GLM:GLM-5.1
Signed-off-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
---
QEMU verification:
- Before patch: dummy0 0x83 -> 0x183 -> 0x383; PROMISC_PROPAGATED and
ALLMULTI_PROPAGATED.
- After patch: dummy0 stayed 0x83; PROMISC_NOT_PROPAGATED and
ALLMULTI_NOT_PROPAGATED.
net/8021q/vlan_dev.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 7aa3af8b10ea..3d1ed61e5a10 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -471,6 +471,9 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
{
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
+ if (!net_eq(dev_net(dev), dev_net(real_dev)))
+ return;
+
if (change & IFF_ALLMULTI)
dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
if (change & IFF_PROMISC)
@@ -479,8 +482,13 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
{
- dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
- dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
+ struct net_device *real_dev = vlan_dev_priv(vlan_dev)->real_dev;
+
+ if (!net_eq(dev_net(vlan_dev), dev_net(real_dev)))
+ return;
+
+ dev_mc_sync(real_dev, vlan_dev);
+ dev_uc_sync(real_dev, vlan_dev);
}
static __be16 vlan_parse_protocol(const struct sk_buff *skb)
--
2.43.0
© 2016 - 2026 Red Hat, Inc.