]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
batman-adv: bla: only purge non-released claims
authorSven Eckelmann <sven@narfation.org>
Wed, 6 May 2026 20:20:51 +0000 (22:20 +0200)
committerSven Eckelmann <sven@narfation.org>
Fri, 8 May 2026 12:28:56 +0000 (14:28 +0200)
When batadv_bla_purge_claims() goes through the list of claims, it is only
traversing the hash list with an rcu_read_lock(). Due to a potential
parallel batadv_claim_put(), it can happen that it encounters a claim which
was actually in the process of being released+freed by
batadv_claim_release(). In this case, backbone_gw is set to NULL before the
delayed RCU kfree is started. Calling batadv_bla_claim_get_backbone_gw() is
then no longer allowed because it would cause a NULL-ptr derefence.

To avoid this, only claims with a valid reference counter must be purged.
All others are already taken care of.

Cc: stable@kernel.org
Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
net/batman-adv/bridge_loop_avoidance.c

index 8b77dd2ecfa419c27fe6f85de1e23913e499ca39..879ab043d57a9f9461799004468a9688f43181c8 100644 (file)
@@ -1288,6 +1288,13 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
 
                rcu_read_lock();
                hlist_for_each_entry_rcu(claim, head, hash_entry) {
+                       /* only purge claims not currently in the process of being released.
+                        * Such claims could otherwise have a NULL-ptr backbone_gw set because
+                        * they already went through batadv_claim_release()
+                        */
+                       if (!kref_get_unless_zero(&claim->refcount))
+                               continue;
+
                        backbone_gw = batadv_bla_claim_get_backbone_gw(claim);
                        if (now)
                                goto purge_now;
@@ -1313,6 +1320,7 @@ purge_now:
                                              claim->addr, claim->vid);
 skip:
                        batadv_backbone_gw_put(backbone_gw);
+                       batadv_claim_put(claim);
                }
                rcu_read_unlock();
        }