HSR/PRP node teardown and the prune paths queue node frees with call_rcu(&node->rcu_head, hsr_free_node_rcu). hsr_free_node_rcu() lives in the hsr module text. hsr_exit() tears down netlink, debugfs and the netdev notifier, but it never calls rcu_barrier(). If a node-free callback is still pending when the module is unloaded, RCU can invoke hsr_free_node_rcu() after the module text has been freed, branching into freed memory. Per Documentation/RCU/checklist.rst, a module that registers callbacks with call_rcu() must call rcu_barrier() in its exit path before it is unloaded; synchronize_rcu() is not sufficient because it only waits for a grace period, not for the queued callbacks to actually run. Add rcu_barrier() at the end of hsr_exit(), after netlink/link teardown has stopped any new callbacks from being queued. Fixes: 415e6367512b ("hsr: Implement more robust duplicate discard for PRP") Cc: stable@vger.kernel.org Signed-off-by: Ali Ahmet Memis --- net/hsr/hsr_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c index 33951d9bd..05d2e5750 100644 --- a/net/hsr/hsr_main.c +++ b/net/hsr/hsr_main.c @@ -179,6 +179,13 @@ static void __exit hsr_exit(void) hsr_netlink_exit(); hsr_debugfs_remove_root(); unregister_netdevice_notifier(&hsr_nb); + + /* Node teardown queues frees via call_rcu(hsr_free_node_rcu), whose + * callback lives in this module. Wait for any still-pending callback + * before the module text is freed. synchronize_rcu() is not enough: + * it waits for a grace period, not for the callbacks to run. + */ + rcu_barrier(); } module_init(hsr_init); -- 2.54.0