]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bridge: Add missing READ_ONCE() annotations around FDB destination port
authorIdo Schimmel <idosch@nvidia.com>
Sun, 17 May 2026 11:50:09 +0000 (14:50 +0300)
committerJakub Kicinski <kuba@kernel.org>
Wed, 20 May 2026 01:13:01 +0000 (18:13 -0700)
When roaming, the FDB destination port can change without holding the
bridge's hash lock. Therefore, add missing READ_ONCE() annotations in
both RCU readers and readers that hold the lock. In the latter case, the
annotation is not needed in places where the FDB entry was already
validated to be a local entry since such entries cannot roam.

Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260517115009.175163-1-idosch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_input.c

index a35ceae0a6f2c2520d1191d7ddc8b9d7b88a6e73..e7f343ab22d379992d4fb545fdc72806fc7d8b1b 100644 (file)
@@ -107,7 +107,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                else
                        br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid);
        } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) {
-               br_forward(dst->dst, skb, false, true);
+               br_forward(READ_ONCE(dst->dst), skb, false, true);
        } else {
                br_flood(br, skb, BR_PKT_UNICAST, false, true, vid);
        }
index ac81e58d5f70c4ff7969c6189d7e520208517089..a114373c98163d1e81b090b9c799adcb1bfeed77 100644 (file)
@@ -470,7 +470,8 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
        spin_lock_bh(&br->hash_lock);
        vg = nbp_vlan_group(p);
        hlist_for_each_entry(f, &br->fdb_list, fdb_node) {
-               if (f->dst == p && test_bit(BR_FDB_LOCAL, &f->flags) &&
+               if (READ_ONCE(f->dst) == p &&
+                   test_bit(BR_FDB_LOCAL, &f->flags) &&
                    !test_bit(BR_FDB_ADDED_BY_USER, &f->flags)) {
                        /* delete old one */
                        fdb_delete_local(br, p, f);
@@ -878,7 +879,7 @@ void br_fdb_delete_by_port(struct net_bridge *br,
 
        spin_lock_bh(&br->hash_lock);
        hlist_for_each_entry_safe(f, tmp, &br->fdb_list, fdb_node) {
-               if (f->dst != p)
+               if (READ_ONCE(f->dst) != p)
                        continue;
 
                if (!do_all)
@@ -1631,7 +1632,7 @@ void br_fdb_clear_offload(const struct net_device *dev, u16 vid)
 
        spin_lock_bh(&p->br->hash_lock);
        hlist_for_each_entry(f, &p->br->fdb_list, fdb_node) {
-               if (f->dst == p && f->key.vlan_id == vid)
+               if (READ_ONCE(f->dst) == p && f->key.vlan_id == vid)
                        clear_bit(BR_FDB_OFFLOADED, &f->flags);
        }
        spin_unlock_bh(&p->br->hash_lock);
index 2cbae0f9ae1f030fd5fdf43495f5ee71d7c630ac..470615675bdc03ca181b72159a1bcfc7b9d7a6a7 100644 (file)
@@ -223,7 +223,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 
                if (now != READ_ONCE(dst->used))
                        WRITE_ONCE(dst->used, now);
-               br_forward(dst->dst, skb, local_rcv, false);
+               br_forward(READ_ONCE(dst->dst), skb, local_rcv, false);
        } else {
                if (!mcast_hit)
                        br_flood(br, skb, pkt_type, local_rcv, false, vid);