A malicious actor behind one bridge port may spam the kernel with OGMs with
a random source MAC address, each of which will create a BLA claim, each of
which is 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 orig_learned, and a limit in orig_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 | 11 +++++++++++
 net/batman-adv/mesh-interface.c        |  3 +++
 net/batman-adv/netlink.c               | 10 ++++++++++
 net/batman-adv/types.h                 |  6 ++++++
 5 files changed, 36 insertions(+)

diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h
index 4188d83c..65d1c0eb 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 claim
+        * 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 8bb8dec6..f39b02f9 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -320,6 +320,7 @@ batadv_bla_del_backbone_claims(struct 
batadv_bla_backbone_gw *backbone_gw)
 
                        hlist_del_rcu(&claim->hash_entry);
                        batadv_claim_put(claim);
+                       atomic_dec(&backbone_gw->bat_priv->bla_claim_learned);
                }
                spin_unlock_bh(list_lock);
        }
@@ -700,7 +701,9 @@ static void batadv_bla_add_claim(struct batadv_priv 
*bat_priv,
        struct batadv_bla_backbone_gw *old_backbone_gw;
        struct batadv_bla_claim *claim;
        struct batadv_bla_claim search_claim;
+       u32 bla_claim_max_learned;
        bool remove_crc = false;
+       int bla_claim_learned;
        int hash_added;
 
        ether_addr_copy(search_claim.addr, mac);
@@ -709,6 +712,11 @@ static void batadv_bla_add_claim(struct batadv_priv 
*bat_priv,
 
        /* create a new claim entry if it does not exist yet. */
        if (!claim) {
+               bla_claim_max_learned = 
READ_ONCE(bat_priv->bla_claim_max_learned);
+               bla_claim_learned = atomic_read(&bat_priv->bla_claim_learned);
+               if (bla_claim_max_learned && bla_claim_learned >= 
bla_claim_max_learned)
+                       return;
+
                claim = kzalloc_obj(*claim, GFP_ATOMIC);
                if (!claim)
                        return;
@@ -721,6 +729,8 @@ static void batadv_bla_add_claim(struct batadv_priv 
*bat_priv,
                claim->backbone_gw = backbone_gw;
                kref_init(&claim->refcount);
 
+               atomic_inc(&bat_priv->bla_claim_learned);
+
                batadv_dbg(BATADV_DBG_BLA, bat_priv,
                           "%s(): adding new entry %pM, vid %d to hash ...\n",
                           __func__, mac, batadv_print_vid(vid));
@@ -735,6 +745,7 @@ static void batadv_bla_add_claim(struct batadv_priv 
*bat_priv,
                        /* only local changes happened. */
                        batadv_backbone_gw_put(backbone_gw);
                        kfree(claim);
+                       atomic_dec(&bat_priv->bla_claim_learned);
                        return;
                }
        } else {
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 1594a2d6..8fd47cef 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -793,6 +793,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 5d4bccdc..8cafbac5 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -151,6 +151,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 },
 };
 
 /**
@@ -298,6 +299,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
@@ -493,6 +498,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 c091b19e..ddd9f1e0 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1662,6 +1662,12 @@ struct batadv_priv {
        /** @bla_backbone_learned: current number of learned backbone_gw 
entries */
        atomic_t bla_backbone_learned;
 
+       /** @bla_claim_max_learned: Maximum number of claim */
+       u32 bla_claim_max_learned;
+
+       /** @bla_claim_learned: current number of learned claim entries */
+       atomic_t bla_claim_learned;
+
        /** @bla: bridge loop avoidance data */
        struct batadv_priv_bla bla;
 #endif

-- 
2.47.3

Reply via email to