Subject: Re: [PATCH net v3 1/1] net: l3mdev: Reject non-L3 uppers in slave helpers

From: Ido Schimmel <[email-masked]>
Date: Mon, 20 Apr 2026 14:32:08 +0300

On Sun, Apr 19, 2026 at 10:53:32PM +0800, Ren Wei wrote:
> From: Haoze Xie <[email-masked]>
> 
> Several l3mdev slave-side helpers resolve an upper device and then use
> l3mdev_ops without first proving that the resolved device is still a
> valid L3 master.
> 
> During slave transition, an RCU reader can transiently observe an upper
> that is not an L3 master. Guard the affected slave-resolved paths by
> requiring the resolved upper to still be an L3 master before using
> l3mdev_ops, while keeping existing L3 RX handler providers intact.
> 
> Fixes: fdeea7be88b1 ("net: vrf: Set slave's private flag before linking")
> Cc: [email-masked]
> Reported-by: Yifan Wu <[email-masked]>
> Reported-by: Juefei Pu <[email-masked]>
> Co-developed-by: Yuan Tan <[email-masked]>
> Signed-off-by: Yuan Tan <[email-masked]>
> Suggested-by: Xin Liu <[email-masked]>
> Tested-by: Haoze Xie <[email-masked]>
> Signed-off-by: Haoze Xie <[email-masked]>
> Signed-off-by: Ao Zhou <[email-masked]>

I think it's fine for net:

Reviewed-by: Ido Schimmel <[email-masked]>

We can try a more general approach in net-next which ensures that RCU
readers don't see different master devices within an RCU read-side
critical section. Something like [1]. I tested it (without your patch)
using the reproducer and was not able to trigger the bug.

I am aware that there are more places where we can unlink a device from
its master (e.g., deleting a master device), but most / all of them
(needs auditing) result in a synchronize_rcu() before releasing RTNL.

On my machine, the time it takes to unlink 1k devices from their master
increased from 0.96 seconds to 1.22 seconds (on average), which is
probably fine.

[1]
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 69daba3ddaf0..23657a11c66d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2970,6 +2970,7 @@ static int do_set_master(struct net_device *dev, int ifindex,
                        netdev_lock_ops(dev);
                        if (err)
                                return err;
+                       synchronize_net();
                } else {
                        return -EOPNOTSUPP;
                }