]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bonding: alb: re-check primary_is_promisc under RTNL in bond_alb_monitor
authorXiang Mei (Microsoft) <xmei5@asu.edu>
Sat, 25 Jul 2026 23:39:30 +0000 (23:39 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Jul 2026 23:16:48 +0000 (16:16 -0700)
bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and
takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the
active slave. In that window the active slave can change under RTNL
(RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()),
which already drops the promiscuity and clears primary_is_promisc. The
monitor still acts on the stale decision: if the slave was removed with no
failover, curr_active_slave is now NULL and the deref faults; if it failed
over, the stale dev_set_promiscuity(-1) underflows the new slave's
promiscuity counter and pins it in IFF_PROMISC.

  Oops: general protection fault, probably for non-canonical address ...
  KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
  Workqueue: b42 bond_alb_monitor
  RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
   process_one_work (kernel/workqueue.c:3322)
   worker_thread (kernel/workqueue.c:3486)
   kthread (kernel/kthread.c:436)
   ret_from_fork (arch/x86/kernel/process.c:158)
  Kernel panic - not syncing: Fatal exception

Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so
the monitor only undoes an increment it still owns. The other bonding
monitors already re-read state under RTNL in their commit phase
(bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only
one acting on the pre-trylock decision.

Fixes: d0e81b7e2246 ("bonding: Acquire correct locks in alb for promisc change")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Acked-by: Jay Vosburgh <jv@jvosburgh.net>
Link: https://patch.msgid.link/20260725233930.2957317-1-xmei5@asu.edu
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/bonding/bond_alb.c

index 2d37b07c8215cbcfefe237d87ca6aeee1c8d335d..839f7482dc1823b12a13437a4b6639e3b63d46ec 100644 (file)
@@ -1534,8 +1534,8 @@ void bond_alb_monitor(struct work_struct *work)
        struct bonding *bond = container_of(work, struct bonding,
                                            alb_work.work);
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+       struct slave *slave, *curr;
        struct list_head *iter;
-       struct slave *slave;
 
        if (!bond_has_slaves(bond)) {
                atomic_set(&bond_info->tx_rebalance_counter, 0);
@@ -1597,9 +1597,11 @@ void bond_alb_monitor(struct work_struct *work)
                         * because a slave was disabled then
                         * it can now leave promiscuous mode.
                         */
-                       dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
-                                           -1);
-                       bond_info->primary_is_promisc = 0;
+                       curr = rtnl_dereference(bond->curr_active_slave);
+                       if (bond_info->primary_is_promisc && curr) {
+                               dev_set_promiscuity(curr->dev, -1);
+                               bond_info->primary_is_promisc = 0;
+                       }
 
                        rtnl_unlock();
                        rcu_read_lock();