list_del_rcu() deliberately leaves the removed key list node intact so that concurrent ieee80211_iter_keys_rcu() readers can advance to the next key. The batch removal paths immediately reuse that same node for a private free list, overwriting its next pointer before synchronize_net(). Add a separate list node for batched key destruction and use it in all existing batch removal paths. This preserves the RCU list links until the grace period completes. Fixes: ef044763a3ca ("mac80211: add atomic uploaded keys iterator") Cc: stable@vger.kernel.org Assisted-by: Codex:gpt-5 Signed-off-by: Weiming Shi --- net/mac80211/key.c | 8 ++++---- net/mac80211/key.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f45e792abede..a69617d8d1c7 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -1100,7 +1100,7 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, ieee80211_key_replace(key->sdata, NULL, key->sta, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key, NULL); - list_add_tail(&key->list, keys); + list_add_tail(&key->free_list, keys); } ieee80211_debugfs_key_update_default(sdata); @@ -1121,7 +1121,7 @@ void ieee80211_remove_link_keys(struct ieee80211_link_data *link, ieee80211_key_replace(key->sdata, link, key->sta, key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE, key, NULL); - list_add_tail(&key->list, keys); + list_add_tail(&key->free_list, keys); } } @@ -1132,7 +1132,7 @@ void ieee80211_free_key_list(struct ieee80211_local *local, lockdep_assert_wiphy(local->hw.wiphy); - list_for_each_entry_safe(key, tmp, keys, list) + list_for_each_entry_safe(key, tmp, keys, free_list) __ieee80211_key_destroy(key, false); } @@ -1159,7 +1159,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, if (!list_empty(&keys) || force_synchronize) synchronize_net(); - list_for_each_entry_safe(key, tmp, &keys, list) + list_for_each_entry_safe(key, tmp, &keys, free_list) __ieee80211_key_destroy(key, false); if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 826e4e9387c5..f5a97213a559 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -63,6 +63,8 @@ struct ieee80211_key { /* for sdata list */ struct list_head list; + /* for temporary lists during batch removal */ + struct list_head free_list; /* protected by key mutex */ unsigned int flags; -- 2.55.0