[PATCH batadv] batman-adv: bla: fix freeing of claims on meshif deletion

Sven Eckelmann <[email protected]> Wed, 22 Jul 2026 12:08:09 +0200
Newsgroups org.open-mesh.lists.batman
Message-ID <[email protected]>
When the mesh interface is getting deleted, then
batadv_bla_del_backbone_claims() (via batadv_bla_purge_backbone_gw()) could
make sure that all claims gets removed. But this function is only executed
when bat_priv->bla.claim_hash is not NULL. And since batadv_bla_free() is
always setting it to NULL before it is (indirectly) called, it was never
actually executed.

But the batadv_bla_purge_claims() -> batadv_handle_unclaim() is at the
moment too fragile because the BLA code is not handling the rehashing in
batadv_bla_update_orig_address(). The stored backbone address doesn't have
to be the one actually used for the hash bucket selection during the
initial adding of the backbone. The batadv_handle_unclaim() can therefore
fail to find the respective backbone for the unclaim and then stop the
deletion.

But the actual backbone_gw object is not needed for the unclaim because all
relevant information is always provided by the caller. And the check for
the existence of the backbone_gw doesn't provide any additional security
check for the deletion of a claim.

Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code")
Signed-off-by: Sven Eckelmann <[email protected]>
---
Problem was caused by https://www.open-mesh.org/issues/452. Was seen with
following test configuration:

    #! /bin/sh
    
    set -e
    export PATH="/host/batctl/:$PATH"
    
    echo disabled loading
    rmmod batman-adv || true
    insmod /host/batman-adv/net/batman-adv/batman-adv.ko
    
    ip link set up dummy0
    
    batctl ra BATMAN_IV
    batctl meshif bat0 interface create
    batctl if add dummy0
    batctl if add enp0s1
    ip link set up dev enp0s3
    ip link set up dev bat0
    ip link show dev bat0
    batctl n|head -n1
    batctl b 1
    
    MAC_PART="$(ip link show enp0s1 | awk "/ether/ {print \$2}"| sed -e "s/.*://" -e "s/[\\n\\ ].*//"|awk "{print (\"0x\"\$1)*1 }")"
    IP_PART="$(echo $MAC_PART|awk "{ print \$1 }")"
    ip addr replace 192.168.42.${IP_PART}/24 dev bat0
    
    ip link add link bat0 name bat0.10 type vlan id 10
    ip link add link bat0 name bat0.0 type vlan id 0
    ip link set up dev bat0.0
    ip link set up dev bat0.10
    ip addr replace 192.168.43.${IP_PART}/24 dev bat0.0
    ip addr replace 192.168.44.${IP_PART}/24 dev bat0.10
    
    ip link add  dev br0 type bridge
    ip link set up dev br0
    ip addr replace 192.168.45.${IP_PART}/24 dev br0
    
    ip link set master br0 bat0
    
    ip link add veth-in type veth peer name veth-out
    ip link set master br0 dev veth-out
    ip link set up veth-out
    ip link set up veth-in
    ip addr replace 192.168.46.${IP_PART}/24 dev veth-in

After it was running for a while (with an uplink to FFV), the interface was
deleted:

    ip link del dev bat0

And then the memory was scanned:

    $ echo scan > /sys/kernel/debug/kmemleak
    $ sleep 5
    $ cat /sys/kernel/debug/kmemleak
    unreferenced object 0xffff88800d243900 (size 192):
      comm "softirq", pid 0, jiffies 4294893474
      hex dump (first 32 bytes):
        d4 0a dc 8a 32 98 00 00 00 02 94 0e 80 88 ff ff  ....2...........
        00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00  .....N..........
      backtrace (crc abaa484d):
        kmemleak_alloc+0x55/0xa0
        __kmalloc_cache_noprof+0x2b4/0x590
        batadv_bla_add_claim+0x4d3/0x12d0 [batman_adv]
        batadv_handle_claim.isra.0+0x52/0x2f0 [batman_adv]
        batadv_bla_rx+0xbfd/0x1110 [batman_adv]
        batadv_interface_rx+0x402/0xac0 [batman_adv]
        batadv_recv_mcast_packet+0x3ee/0x6b0 [batman_adv]
        batadv_batman_skb_recv+0x40e/0x5e0 [batman_adv]
        __netif_receive_skb_list_core+0x61f/0x9c0
        netif_receive_skb_list_internal+0x626/0x1070
        napi_complete_done+0x1ba/0x820
        virtnet_poll+0xc5d/0x18a0
        __napi_poll.constprop.0+0xa3/0x520
        net_rx_action+0x452/0x1170
        handle_softirqs+0x1cb/0x880
        irq_exit_rcu+0x112/0x1a0
    unreferenced object 0xffff88800d243400 (size 192):
      comm "softirq", pid 0, jiffies 4294893480
      hex dump (first 32 bytes):
        be dd b4 e6 68 a8 00 00 00 02 94 0e 80 88 ff ff  ....h...........
        00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00  .....N..........
      backtrace (crc fdf62603):
        kmemleak_alloc+0x55/0xa0
        __kmalloc_cache_noprof+0x2b4/0x590
        batadv_bla_add_claim+0x4d3/0x12d0 [batman_adv]
        batadv_handle_claim.isra.0+0x52/0x2f0 [batman_adv]
        batadv_bla_rx+0xbfd/0x1110 [batman_adv]
        batadv_interface_rx+0x402/0xac0 [batman_adv]
        batadv_recv_mcast_packet+0x3ee/0x6b0 [batman_adv]
        batadv_batman_skb_recv+0x40e/0x5e0 [batman_adv]
        __netif_receive_skb_list_core+0x61f/0x9c0
        netif_receive_skb_list_internal+0x626/0x1070
        napi_complete_done+0x1ba/0x820
        virtnet_poll+0xc5d/0x18a0
        __napi_poll.constprop.0+0xa3/0x520
        net_rx_action+0x452/0x1170
        handle_softirqs+0x1cb/0x880
        run_ksoftirqd+0x32/0x60
    ....

The problem is not visible when I only have one interface added and thus
no-rehash is needed while the bat0 interface is deleted.
---
 net/batman-adv/bridge_loop_avoidance.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index f231afbe..54f4e432 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -949,26 +949,18 @@ static bool batadv_handle_unclaim(struct batadv_priv *bat_priv,
 				  const u8 *backbone_addr, const u8 *claim_addr,
 				  unsigned short vid)
 {
-	struct batadv_bla_backbone_gw *backbone_gw;
-
 	/* unclaim in any case if it is our own */
 	if (primary_if && batadv_compare_eth(backbone_addr,
 					     primary_if->net_dev->dev_addr))
 		batadv_bla_send_claim(bat_priv, claim_addr, vid,
 				      BATADV_CLAIM_TYPE_UNCLAIM);
 
-	backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
-
-	if (!backbone_gw)
-		return true;
-
 	/* this must be an UNCLAIM frame */
 	batadv_dbg(BATADV_DBG_BLA, bat_priv,
 		   "%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
-		   claim_addr, batadv_print_vid(vid), backbone_gw->orig);
+		   claim_addr, batadv_print_vid(vid), backbone_addr);
 
 	batadv_bla_del_claim(bat_priv, claim_addr, vid);
-	batadv_backbone_gw_put(backbone_gw);
 	return true;
 }
 

---
base-commit: 95b6f66b2659f617ce1937e790f48dc578ee014c
change-id: 20260722-bla-claim-cleanup-5ba2a844e274

Best regards,
--  
Sven Eckelmann <[email protected]>