]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Jan 2026 10:18:37 +0000 (11:18 +0100)
[ Upstream commit b25a0b4a2193407aa72a4cd1df66a7ed07dd4f1e ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/bridge/br_fdb.c
net/bridge/br_input.c

index 642b8ccaae8ea2cd534514e575702ae3b1c30d1d..9dd405b64fcc9a171423b548a67061c4ca47dd4d 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 void fdb_rcu_free(struct rcu_head *head)
@@ -133,9 +133,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;
@@ -552,7 +552,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)) {
@@ -829,6 +829,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));
@@ -858,8 +859,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;
        }
@@ -907,8 +911,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);
                        }
 
@@ -1146,10 +1150,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);
        }
 
@@ -1462,7 +1466,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);
@@ -1471,7 +1475,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 2eb2bb66438859868a396e57c1924dff63b65fc1..8c26605c4cc1e3ff6f3109df39ad3dd98648b4ec 100644 (file)
@@ -207,8 +207,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)