net_shaper_flush() frees shaper objects with plain kfree() after xa_erase(), but net_shaper_nl_get_doit() and net_shaper_nl_get_dumpit() read shaper objects under rcu_read_lock() via xa_load(). This creates a use-after-free window where an RCU reader may still hold a pointer to a shaper object that has been freed. The race is: CPU 0 (reader) CPU 1 (flush/unregister) rcu_read_lock() shaper = xa_load(...) xa_lock() // shaper points to valid obj __xa_erase(...) kfree(shaper) <- frees immediately net_shaper_fill_one(shaper) xa_unlock() // use-after-free rcu_read_unlock() Other code paths in the same file already use kfree_rcu() correctly (net_shaper_pre_insert error path, net_shaper_notify_down, net_shaper_cap_pair_update, and net_shaper_rollback as of commit b8d7519352ba). The struct net_shaper already contains an rcu_head field. Fix by replacing kfree() with kfree_rcu() in net_shaper_flush() to defer freeing until after the RCU grace period. Found by source code audit. Fixes: ff7d4deb1f3e ("net-shapers: implement shaper cleanup on queue deletion") Cc: Paolo Abeni Cc: stable@vger.kernel.org Signed-off-by: Tristan Madani --- net/shaper/shaper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c index dea9270f3e57d..92a6939787240 100644 --- a/net/shaper/shaper.c +++ b/net/shaper/shaper.c @@ -1475,7 +1475,7 @@ static void net_shaper_flush(struct net_shaper_binding *binding) xa_lock(&hierarchy->shapers); xa_for_each(&hierarchy->shapers, index, cur) { __xa_erase(&hierarchy->shapers, index); - kfree(cur); + kfree_rcu(cur, rcu); } xa_unlock(&hierarchy->shapers); -- 2.47.3