Skip to content

Commit f0a6fd1

Browse files
committed
cfg80211: fix race in netlink owner interface destruction
My previous fix here to fix the deadlock left a race where the exact same deadlock (see the original commit referenced below) can still happen if cfg80211_destroy_ifaces() already runs while nl80211_netlink_notify() is still marking some interfaces as nl_owner_dead. The race happens because we have two loops here - first we dev_close() all the netdevs, and then we destroy them. If we also have two netdevs (first one need only be a wdev though) then we can find one during the first iteration, close it, and go to the second iteration -- but then find two, and try to destroy also the one we didn't close yet. Fix this by only iterating once. Reported-by: Toke Høiland-Jørgensen <[email protected]> Fixes: ea6b209 ("cfg80211: fix locking in netlink owner interface destruction") Tested-by: Toke Høiland-Jørgensen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Johannes Berg <[email protected]>
1 parent 5f06f6b commit f0a6fd1

File tree

1 file changed

+4
-13
lines changed

1 file changed

+4
-13
lines changed

net/wireless/core.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Copyright 2006-2010 Johannes Berg <[email protected]>
66
* Copyright 2013-2014 Intel Mobile Communications GmbH
77
* Copyright 2015-2017 Intel Deutschland GmbH
8-
* Copyright (C) 2018-2021 Intel Corporation
8+
* Copyright (C) 2018-2022 Intel Corporation
99
*/
1010

1111
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -332,29 +332,20 @@ static void cfg80211_event_work(struct work_struct *work)
332332
void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
333333
{
334334
struct wireless_dev *wdev, *tmp;
335-
bool found = false;
336335

337336
ASSERT_RTNL();
338337

339-
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
338+
list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
340339
if (wdev->nl_owner_dead) {
341340
if (wdev->netdev)
342341
dev_close(wdev->netdev);
343-
found = true;
344-
}
345-
}
346-
347-
if (!found)
348-
return;
349342

350-
wiphy_lock(&rdev->wiphy);
351-
list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) {
352-
if (wdev->nl_owner_dead) {
343+
wiphy_lock(&rdev->wiphy);
353344
cfg80211_leave(rdev, wdev);
354345
rdev_del_virtual_intf(rdev, wdev);
346+
wiphy_unlock(&rdev->wiphy);
355347
}
356348
}
357-
wiphy_unlock(&rdev->wiphy);
358349
}
359350

360351
static void cfg80211_destroy_iface_wk(struct work_struct *work)

0 commit comments

Comments
 (0)