The following commit has been merged in the master branch:
commit f12b69d8f22824a07f17c1399c99757072de73e0
Author: Sven Eckelmann <[email protected]>
Date:   Sat Sep 27 19:39:08 2025 +0200

    batman-adv: Release references to inactive interfaces
    
    Trying to dump the originators or the neighbors via netlink for a meshif
    with an inactive primary interface is not allowed. The dump functions were
    checking this correctly but they didn't handle non-existing primary
    interfaces and existing _inactive_ interfaces differently.
    
    (Primary) batadv_hard_ifaces hold a references to a net_device. And
    accessing them is only allowed when either being in a RCU/spinlock
    protected section or when holding a valid reference to them. The netlink
    dump functions use the latter.
    
    But because the missing specific error handling for inactive primary
    interfaces, the reference was never dropped. This reference counting error
    was only detected when the interface should have been removed from the
    system:
    
      unregister_netdevice: waiting for batadv_slave_0 to become free. Usage 
count = 2
    
    Cc: [email protected]
    Fixes: 6ecc4fd6c2f4 ("batman-adv: netlink: reduce duplicate code by 
returning interfaces")
    Reported-by: [email protected]
    Reported-by: Tetsuo Handa <[email protected]>
    Signed-off-by: Sven Eckelmann <[email protected]>
    Signed-off-by: Simon Wunderlich <[email protected]>

diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index a464ff96b9291..ed89d7fd1e7f4 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -764,11 +764,16 @@ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct 
netlink_callback *cb)
        bat_priv = netdev_priv(mesh_iface);
 
        primary_if = batadv_primary_if_get_selected(bat_priv);
-       if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
+       if (!primary_if) {
                ret = -ENOENT;
                goto out_put_mesh_iface;
        }
 
+       if (primary_if->if_status != BATADV_IF_ACTIVE) {
+               ret = -ENOENT;
+               goto out_put_primary_if;
+       }
+
        hard_iface = batadv_netlink_get_hardif(bat_priv, cb);
        if (IS_ERR(hard_iface) && PTR_ERR(hard_iface) != -ENONET) {
                ret = PTR_ERR(hard_iface);
@@ -1333,11 +1338,16 @@ int batadv_orig_dump(struct sk_buff *msg, struct 
netlink_callback *cb)
        bat_priv = netdev_priv(mesh_iface);
 
        primary_if = batadv_primary_if_get_selected(bat_priv);
-       if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
+       if (!primary_if) {
                ret = -ENOENT;
                goto out_put_mesh_iface;
        }
 
+       if (primary_if->if_status != BATADV_IF_ACTIVE) {
+               ret = -ENOENT;
+               goto out_put_primary_if;
+       }
+
        hard_iface = batadv_netlink_get_hardif(bat_priv, cb);
        if (IS_ERR(hard_iface) && PTR_ERR(hard_iface) != -ENONET) {
                ret = PTR_ERR(hard_iface);

-- 
LinuxNextTracking

Reply via email to