VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46233

CVE-2026-46233

Description

In the Linux kernel, the following vulnerability has been resolved:

batman-adv: bla: only purge non-released claims

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.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A race condition in batman-adv's bridge loop avoidance (BLA) claim purging can cause a NULL pointer dereference, leading to a kernel crash.

Vulnerability

In the Linux kernel's batman-adv module, the function batadv_bla_purge_claims() traverses the hash list of claims under an RCU read lock. A race condition exists where a parallel batadv_claim_put() can release a claim, setting its backbone_gw pointer to NULL before the delayed RCU kfree. This causes batadv_bla_claim_get_backbone_gw() to dereference a NULL pointer, leading to a kernel crash. The vulnerability affects all kernel versions with batman-adv BLA support prior to the fix in commit 7b7ebb7222a5524ce58e48cc9c6d688320ea6cfe [1].

Exploitation

An attacker must be able to trigger the race window between the claim purging and the claim release. This requires local access to the system with the ability to manipulate batman-adjacent network interfaces or trigger BLA claim operations. The race is timing-dependent; the attacker would need to cause a claim to be released while the purging function is iterating over the claims list. No authentication is required beyond local network access to the batman-adv mesh.

Impact

Successful exploitation results in a NULL pointer dereference in the kernel, causing a denial of service (system crash or hang). The vulnerability does not appear to allow arbitrary code execution or privilege escalation, as the dereference is a read of a NULL pointer leading to a panic. The impact is limited to availability.

Mitigation

The fix is included in Linux kernel stable commit 7b7ebb7222a5524ce58e48cc9c6d688320ea6cfe [1]. Users should update to a kernel version containing this commit. No workaround is available; the vulnerability is resolved by ensuring that only claims with a valid reference counter are purged. The fix was applied to the stable kernel tree; users should apply the latest stable updates.

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

10
cf6b60401159

batman-adv: bla: only purge non-released claims

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSven EckelmannFixed in 7.1-rc4via kernel-cna
2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
7b8fbcee3184

batman-adv: bla: only purge non-released claims

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSven EckelmannFixed in 6.6.140via kernel-cna
2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index c4f364831df8a6..2da608d51d9187 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index c4f364831df8a6..2da608d51d9187 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
7b7ebb7222a5

batman-adv: bla: only purge non-released claims

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSven EckelmannFixed in 6.12.90via kernel-cna
2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 5f106b7299fb77..d67bcbddd63f54 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 5f106b7299fb77..d67bcbddd63f54 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
b65365d2b1e6

batman-adv: bla: only purge non-released claims

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitSven EckelmannFixed in 6.18.32via kernel-cna
2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 41313ea2193585..fd5ba288c7b121 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -1289,6 +1289,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;
    @@ -1314,6 +1321,7 @@ purge_now:
     					      claim->addr, claim->vid);
     skip:
     			batadv_backbone_gw_put(backbone_gw);
    +			batadv_claim_put(claim);
     		}
     		rcu_read_unlock();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 41313ea2193585..fd5ba288c7b121 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -1289,6 +1289,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;
    @@ -1314,6 +1321,7 @@ purge_now:
     					      claim->addr, claim->vid);
     skip:
     			batadv_backbone_gw_put(backbone_gw);
    +			batadv_claim_put(claim);
     		}
     		rcu_read_unlock();
     	}
    -- 
    cgit 1.3-korg
    
    
    
ab3dbd07a809

batman-adv: bla: only purge non-released claims

2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
ab3dbd07a809

batman-adv: bla: only purge non-released claims

2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
7b8fbcee3184

batman-adv: bla: only purge non-released claims

2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index c4f364831df8a6..2da608d51d9187 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index c4f364831df8a6..2da608d51d9187 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
7b7ebb7222a5

batman-adv: bla: only purge non-released claims

2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 5f106b7299fb77..d67bcbddd63f54 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 5f106b7299fb77..d67bcbddd63f54 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
b65365d2b1e6

batman-adv: bla: only purge non-released claims

2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 41313ea2193585..fd5ba288c7b121 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -1289,6 +1289,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;
    @@ -1314,6 +1321,7 @@ purge_now:
     					      claim->addr, claim->vid);
     skip:
     			batadv_backbone_gw_put(backbone_gw);
    +			batadv_claim_put(claim);
     		}
     		rcu_read_unlock();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 41313ea2193585..fd5ba288c7b121 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -1289,6 +1289,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;
    @@ -1314,6 +1321,7 @@ purge_now:
     					      claim->addr, claim->vid);
     skip:
     			batadv_backbone_gw_put(backbone_gw);
    +			batadv_claim_put(claim);
     		}
     		rcu_read_unlock();
     	}
    -- 
    cgit 1.3-korg
    
    
    
cf6b60401159

batman-adv: bla: only purge non-released claims

2 files changed · +16 2
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    
  • net/batman-adv/bridge_loop_avoidance.c+8 1 modified
    diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
    index 8b77dd2ecfa419..879ab043d57a9f 100644
    --- a/net/batman-adv/bridge_loop_avoidance.c
    +++ b/net/batman-adv/bridge_loop_avoidance.c
    @@ -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();
     	}
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing reference-count check in batadv_bla_purge_claims() allows accessing a claim whose backbone_gw has been set to NULL by a concurrent release, leading to a NULL-ptr dereference."

Attack vector

An attacker on the same batman-adv mesh network can trigger a race condition between `batadv_bla_purge_claims()` (which walks the claim hash list under RCU) and a parallel `batadv_claim_put()` / `batadv_claim_release()` that sets `backbone_gw` to NULL before the RCU-delayed kfree. When the purge loop calls `batadv_bla_claim_get_backbone_gw()` on such a partially-released claim, it dereferences a NULL pointer, causing a kernel NULL-ptr dereference. No special privileges beyond mesh network access are required; the race occurs during normal bridge loop avoidance (BLA) claim lifecycle operations.

Affected code

The vulnerability resides in `net/batman-adv/bridge_loop_avoidance.c` in the function `batadv_bla_purge_claims()`. The function traverses the claim hash list under an `rcu_read_lock()` and calls `batadv_bla_claim_get_backbone_gw()` on each claim without first verifying that the claim is not already in the process of being released [patch_id=2897547].

What the fix does

The patch adds a `kref_get_unless_zero(&claim->refcount)` check at the top of the purge loop in `batadv_bla_purge_claims()` [patch_id=2897547]. If the claim's reference count is already zero (meaning it is in the process of being released), the loop skips it via `continue`. For claims that pass this check, a matching `batadv_claim_put()` is added after the purge logic completes to balance the acquired reference. This prevents the NULL-ptr dereference by ensuring only claims with a valid reference count are accessed for their `backbone_gw` pointer.

Preconditions

  • networkThe attacker must be able to send batman-adv mesh packets that trigger BLA claim creation and release on the target node
  • configThe target kernel must have batman-adv bridge loop avoidance (BLA) enabled

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.