]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: bridge: annotate data-races around fdb->{updated,used}
authorEric Dumazet <edumazet@google.com>
Thu, 8 Jan 2026 09:38:06 +0000 (09:38 +0000)
committerJakub Kicinski <kuba@kernel.org>
Sat, 10 Jan 2026 01:36:21 +0000 (17:36 -0800)
fdb->updated and fdb->used are read and written locklessly.

Add READ_ONCE()/WRITE_ONCE() annotations.

Fixes: 31cbc39b6344 ("net: bridge: add option to allow activity notifications for any fdb entries")
Reported-by: syzbot+bfab43087ad57222ce96@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/695e3d74.050a0220.1c677c.035f.GAE@google.com/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260108093806.834459-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/bridge/br_fdb.c
net/bridge/br_input.c

index 58d22e2b85fc3551bd5aec9c20296ddfcecaa040..0501ffcb8a3ddb21a19254915564b4000b6b6911 100644 (file)
@@ -70,7 +70,7 @@ static inline int has_expired(const struct net_bridge *br,
 {
        return !test_bit(BR_FDB_STATIC, &fdb->flags) &&
               !test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags) &&
-              time_before_eq(fdb->updated + hold_time(br), jiffies);
+              time_before_eq(READ_ONCE(fdb->updated) + hold_time(br), jiffies);
 }
 
 static int fdb_to_nud(const struct net_bridge *br,
@@ -126,9 +126,9 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br,
        if (nla_put_u32(skb, NDA_FLAGS_EXT, ext_flags))
                goto nla_put_failure;
 
-       ci.ndm_used      = jiffies_to_clock_t(now - fdb->used);
+       ci.ndm_used      = jiffies_to_clock_t(now - READ_ONCE(fdb->used));
        ci.ndm_confirmed = 0;
-       ci.ndm_updated   = jiffies_to_clock_t(now - fdb->updated);
+       ci.ndm_updated   = jiffies_to_clock_t(now - READ_ONCE(fdb->updated));
        ci.ndm_refcnt    = 0;
        if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
                goto nla_put_failure;
@@ -551,7 +551,7 @@ void br_fdb_cleanup(struct work_struct *work)
         */
        rcu_read_lock();
        hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
-               unsigned long this_timer = f->updated + delay;
+               unsigned long this_timer = READ_ONCE(f->updated) + delay;
 
                if (test_bit(BR_FDB_STATIC, &f->flags) ||
                    test_bit(BR_FDB_ADDED_BY_EXT_LEARN, &f->flags)) {
@@ -924,6 +924,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
 {
        struct net_bridge_fdb_entry *f;
        struct __fdb_entry *fe = buf;
+       unsigned long delta;
        int num = 0;
 
        memset(buf, 0, maxnum*sizeof(struct __fdb_entry));
@@ -953,8 +954,11 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
                fe->port_hi = f->dst->port_no >> 8;
 
                fe->is_local = test_bit(BR_FDB_LOCAL, &f->flags);
-               if (!test_bit(BR_FDB_STATIC, &f->flags))
-                       fe->ageing_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated);
+               if (!test_bit(BR_FDB_STATIC, &f->flags)) {
+                       delta = jiffies - READ_ONCE(f->updated);
+                       fe->ageing_timer_value =
+                               jiffies_delta_to_clock_t(delta);
+               }
                ++fe;
                ++num;
        }
@@ -1002,8 +1006,8 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
                        unsigned long now = jiffies;
                        bool fdb_modified = false;
 
-                       if (now != fdb->updated) {
-                               fdb->updated = now;
+                       if (now != READ_ONCE(fdb->updated)) {
+                               WRITE_ONCE(fdb->updated, now);
                                fdb_modified = __fdb_mark_active(fdb);
                        }
 
@@ -1242,10 +1246,10 @@ static int fdb_add_entry(struct net_bridge *br, struct net_bridge_port *source,
        if (fdb_handle_notify(fdb, notify))
                modified = true;
 
-       fdb->used = jiffies;
+       WRITE_ONCE(fdb->used, jiffies);
        if (modified) {
                if (refresh)
-                       fdb->updated = jiffies;
+                       WRITE_ONCE(fdb->updated, jiffies);
                fdb_notify(br, fdb, RTM_NEWNEIGH, true);
        }
 
@@ -1556,7 +1560,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
                        goto err_unlock;
                }
 
-               fdb->updated = jiffies;
+               WRITE_ONCE(fdb->updated, jiffies);
 
                if (READ_ONCE(fdb->dst) != p) {
                        WRITE_ONCE(fdb->dst, p);
@@ -1565,7 +1569,7 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p,
 
                if (test_and_set_bit(BR_FDB_ADDED_BY_EXT_LEARN, &fdb->flags)) {
                        /* Refresh entry */
-                       fdb->used = jiffies;
+                       WRITE_ONCE(fdb->used, jiffies);
                } else {
                        modified = true;
                }
index 777fa869c1a14453bd1827d545527607fbf95a60..e355a15bf5ab13e603ceed2b99e56ddeffdecbb2 100644 (file)
@@ -221,8 +221,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
                if (test_bit(BR_FDB_LOCAL, &dst->flags))
                        return br_pass_frame_up(skb, false);
 
-               if (now != dst->used)
-                       dst->used = now;
+               if (now != READ_ONCE(dst->used))
+                       WRITE_ONCE(dst->used, now);
                br_forward(dst->dst, skb, local_rcv, false);
        } else {
                if (!mcast_hit)