Commit 628980e5 authored by Martin Willi's avatar Martin Willi Committed by Johannes Berg

mac80211_hwsim: fix locking when iterating radios during ns exit

The cleanup of radios during namespace exit has recently been reworked
to directly delete a radio while temporarily releasing the spinlock,
fixing a race condition between the work-queue execution and namespace
exits. However, the temporary unlock allows unsafe modifications on the
iterated list, resulting in a potential crash when continuing the
iteration of additional radios.

Move radios about to destroy to a temporary list, and clean that up
after releasing the spinlock once iteration is complete.

Fixes: 8cfd36a0 ("mac80211_hwsim: fix use-after-free bug in hwsim_exit_net")
Signed-off-by: default avatarMartin Willi <martin@strongswan.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 30fe6d50
...@@ -3646,6 +3646,7 @@ static __net_init int hwsim_init_net(struct net *net) ...@@ -3646,6 +3646,7 @@ static __net_init int hwsim_init_net(struct net *net)
static void __net_exit hwsim_exit_net(struct net *net) static void __net_exit hwsim_exit_net(struct net *net)
{ {
struct mac80211_hwsim_data *data, *tmp; struct mac80211_hwsim_data *data, *tmp;
LIST_HEAD(list);
spin_lock_bh(&hwsim_radio_lock); spin_lock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(data, tmp, &hwsim_radios, list) { list_for_each_entry_safe(data, tmp, &hwsim_radios, list) {
...@@ -3656,17 +3657,19 @@ static void __net_exit hwsim_exit_net(struct net *net) ...@@ -3656,17 +3657,19 @@ static void __net_exit hwsim_exit_net(struct net *net)
if (data->netgroup == hwsim_net_get_netgroup(&init_net)) if (data->netgroup == hwsim_net_get_netgroup(&init_net))
continue; continue;
list_del(&data->list); list_move(&data->list, &list);
rhashtable_remove_fast(&hwsim_radios_rht, &data->rht, rhashtable_remove_fast(&hwsim_radios_rht, &data->rht,
hwsim_rht_params); hwsim_rht_params);
hwsim_radios_generation++; hwsim_radios_generation++;
}
spin_unlock_bh(&hwsim_radio_lock); spin_unlock_bh(&hwsim_radio_lock);
list_for_each_entry_safe(data, tmp, &list, list) {
list_del(&data->list);
mac80211_hwsim_del_radio(data, mac80211_hwsim_del_radio(data,
wiphy_name(data->hw->wiphy), wiphy_name(data->hw->wiphy),
NULL); NULL);
spin_lock_bh(&hwsim_radio_lock);
} }
spin_unlock_bh(&hwsim_radio_lock);
ida_simple_remove(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net)); ida_simple_remove(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment