[PATCH batadv v3 5/5] batman-adv: limit number of parallel learned BLA claims
Sven Eckelmann <[email protected]> Fri, 24 Jul 2026 08:51:42 +0200
| Newsgroups | org.open-mesh.lists.batman |
|---|---|
| Message-ID | <[email protected]> |
A malicious actor on the backbone Ethernet may spam the kernel with BLA claims using a random source MAC address and a valid group ID (local group ID, or one that exists on the mesh), each of which will create a BLA claim, a dynamic allocation in the kernel. This will at some point exhaust the available memory. Mitigate this by maintaining a per meshif count of those automatically generated entries in bla.claim_learned, and a limit in bla.claim_max_learned. If the limit is hit, new entries are not learned anymore. For backwards compatibility, the default setting of 0 disables the limit. Signed-off-by: Sven Eckelmann <[email protected]> --- include/uapi/linux/batman_adv.h | 6 ++++++ net/batman-adv/bridge_loop_avoidance.c | 21 ++++++++++++++++++--- net/batman-adv/mesh-interface.c | 3 +++ net/batman-adv/netlink.c | 10 ++++++++++ net/batman-adv/types.h | 6 ++++++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h index 33049818..460e75c4 100644 --- a/include/uapi/linux/batman_adv.h +++ b/include/uapi/linux/batman_adv.h @@ -505,6 +505,12 @@ enum batadv_nl_attrs { */ BATADV_ATTR_BLA_BACKBONE_MAX_LEARNED, + /** + * @BATADV_ATTR_BLA_CLAIM_MAX_LEARNED: defines the maximum number of BLA claims + * which can be learned in parallel + */ + BATADV_ATTR_BLA_CLAIM_MAX_LEARNED, + /* add attributes above here, update the policy in netlink.c */ /** diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 949c887b..d8e7d7ad 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -182,6 +182,7 @@ static void batadv_claim_release(struct kref *ref) { struct batadv_bla_backbone_gw *old_backbone_gw; struct batadv_bla_claim *claim; + struct batadv_priv *bat_priv; claim = container_of(ref, struct batadv_bla_claim, refcount); @@ -194,8 +195,10 @@ static void batadv_claim_release(struct kref *ref) old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN); spin_unlock_bh(&old_backbone_gw->crc_lock); + bat_priv = old_backbone_gw->bat_priv; batadv_backbone_gw_put(old_backbone_gw); + atomic_dec(&bat_priv->bla.claim_learned); kfree_rcu(claim, rcu); } @@ -713,6 +716,8 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, struct batadv_bla_backbone_gw *old_backbone_gw; struct batadv_bla_claim search_claim; struct batadv_bla_claim *claim; + u32 bla_claim_max_learned; + int bla_claim_learned; int hash_added; u16 claim_crc; bool changed; @@ -724,9 +729,18 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, /* create a new claim entry if it does not exist yet. */ if (!claim) { - claim = kzalloc_obj(*claim, GFP_ATOMIC); - if (!claim) + bla_claim_max_learned = READ_ONCE(bat_priv->bla.claim_max_learned); + bla_claim_learned = atomic_inc_return(&bat_priv->bla.claim_learned); + if (bla_claim_max_learned && bla_claim_learned > bla_claim_max_learned) { + atomic_dec(&bat_priv->bla.claim_learned); return; + } + + claim = kzalloc_obj(*claim, GFP_ATOMIC); + if (!claim) { + atomic_dec(&bat_priv->bla.claim_learned); + return; + } ether_addr_copy(claim->addr, mac); spin_lock_init(&claim->backbone_lock); @@ -747,8 +761,9 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, &claim->hash_entry); if (unlikely(hash_added != 0)) { - /* only local changes happened. */ batadv_backbone_gw_put(backbone_gw); + atomic_dec(&bat_priv->bla.claim_learned); + /* only local changes happened. */ kfree(claim); return; } diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index 0e313ac8..4d83be55 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -849,6 +849,9 @@ static int batadv_meshif_init_late(struct net_device *dev) atomic_set(&bat_priv->bla.backbone_learned, 0); WRITE_ONCE(bat_priv->bla.backbone_max_learned, 0); + + atomic_set(&bat_priv->bla.claim_learned, 0); + WRITE_ONCE(bat_priv->bla.claim_max_learned, 0); #endif atomic_set(&bat_priv->tp_num, 0); diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index f49d7a5e..f2c7fd8d 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -158,6 +158,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { [BATADV_ATTR_ORIG_MAX_LEARNED] = { .type = NLA_U32 }, [BATADV_ATTR_DAT_MAX_LEARNED] = { .type = NLA_U32 }, [BATADV_ATTR_BLA_BACKBONE_MAX_LEARNED] = { .type = NLA_U32 }, + [BATADV_ATTR_BLA_CLAIM_MAX_LEARNED] = { .type = NLA_U32 }, }; /** @@ -305,6 +306,10 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, if (nla_put_u32(msg, BATADV_ATTR_BLA_BACKBONE_MAX_LEARNED, READ_ONCE(bat_priv->bla.backbone_max_learned))) goto nla_put_failure; + + if (nla_put_u32(msg, BATADV_ATTR_BLA_CLAIM_MAX_LEARNED, + READ_ONCE(bat_priv->bla.claim_max_learned))) + goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BLA */ #ifdef CONFIG_BATMAN_ADV_DAT @@ -500,6 +505,11 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) WRITE_ONCE(bat_priv->bla.backbone_max_learned, nla_get_u32(info->attrs[BATADV_ATTR_BLA_BACKBONE_MAX_LEARNED])); } + + if (info->attrs[BATADV_ATTR_BLA_CLAIM_MAX_LEARNED]) { + WRITE_ONCE(bat_priv->bla.claim_max_learned, + nla_get_u32(info->attrs[BATADV_ATTR_BLA_CLAIM_MAX_LEARNED])); + } #endif /* CONFIG_BATMAN_ADV_BLA */ #ifdef CONFIG_BATMAN_ADV_DAT diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 22d47509..df2d5ccf 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1077,6 +1077,12 @@ struct batadv_priv_bla { /** @backbone_learned: current number of learned backbone_gw entries */ atomic_t backbone_learned; + /** @claim_max_learned: Maximum number of claims */ + u32 claim_max_learned; + + /** @claim_learned: current number of learned claim entries */ + atomic_t claim_learned; + /** * @num_requests_lock: locks update num_requests + * batadv_backbone_gw::state + batadv_backbone_gw::wait_periods update -- 2.47.3