mainline inclusion from mainline-v7.2-rc4 commit 0c2ed186bbe14304415476d6707b747dddcd8583 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17056 CVE: CVE-2026-68404 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- nl80211_netlink_notify() walks the cfg80211 wireless device list when a NETLINK_GENERIC socket is released. If the socket owns a connection, the notifier queues the embedded wdev->disconnect_wk work item. That work is a plain work_struct today. NETDEV_GOING_DOWN cancels it, but a NETLINK_URELEASE notifier that already observed conn_owner_nlportid can queue it after that cancel returns. _cfg80211_unregister_wdev() then removes the wdev from the list and waits for RCU readers, but synchronize_net() does not drain work queued by such a reader. Make the autodisconnect work a wiphy_work instead. The callback already needs the wiphy mutex, and wiphy_work runs under that mutex. This lets teardown cancel pending autodisconnect work while holding the mutex, without a cancel_work_sync() vs. worker locking concern. Also cancel the wiphy work after list_del_rcu() and synchronize_net(). Any NETLINK_URELEASE notifier that had already reached the wdev list has then either queued the work and it is removed, or can no longer find the wdev. Fixes: bd2522b16884 ("cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT") Suggested-by: Johannes Berg <johannes@sipsolutions.net> Assisted-by: Codex:gpt-5.5 Signed-off-by: Cen Zhang <zzzccc427@gmail.com> Link: https://patch.msgid.link/20260706152418.779226-1-zzzccc427@gmail.com Signed-off-by: Johannes Berg <johannes.berg@intel.com> Conflicts: net/wireless/core.c include/net/cfg80211.h net/wireless/core.h net/wireless/nl80211.c net/wireless/sme.c [Upstream commit 0c2ed186bbe14 ("wifi: cfg80211: use wiphy work for socket owner autodisconnect") converts wdev->disconnect_wk from plain work_struct to wiphy_work and relies on wiphy_lock/guard(wiphy) which were introduced in 6.x. OLK-5.10 (5.10 base) does not carry the wiphy_work framework, so this backport keeps disconnect_wk as plain work_struct and applies the equivalent fix in two places: 1. In __cfg80211_unregister_wdev(): keep the existing cancel/flush position (after list_del_rcu() + synchronize_rcu()) but switch flush_work() to cancel_work_sync(). The position must be after synchronize_rcu(): a NETLINK_URELEASE notifier that entered the RCU reader before list_del_rcu will schedule_work(disconnect_wk) before its reader exits, and only a post-synchronize_rcu cancel catches that work. cancel_work_sync also dequeues pending work that flush_work would have executed needlessly. This matches the upstream semantic "cancel after list_del_rcu and synchronize_net". 2. In NETDEV_GOING_DOWN: cancel_work_sync(&wdev->disconnect_wk) after cfg80211_leave() to drop any disconnect_wk queued by a URELEASE notifier before teardown. olk5.10 was missing this cancel entirely. The upstream commit message mentions that wiphy_work is chosen to avoid "a cancel_work_sync() vs. worker locking concern". That concern is specific to the 6.x lock structure where disconnect_wk's work function takes wiphy_lock and teardown holds wiphy_lock while calling cancel_work_sync (the deadlock pattern described in commit 2b0eab425e1f "wifi: cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock"). olk5.10's lock structure is different: cfg80211_autodisconnect_wk only takes wdev->mtx (wdev_lock), and the two cancel_work_sync() call sites added here hold RTNL but not wdev->mtx. There is no lock L that both cancel_work_sync() and the work function need, so the deadlock condition does not apply. ] Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- net/wireless/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index c6c5dd4e3520..1a36b52ed744 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1132,9 +1132,8 @@ static void __cfg80211_unregister_wdev(struct wireless_dev *wdev, bool sync) kfree_sensitive(wdev->wext.keys); wdev->wext.keys = NULL; #endif - /* only initialized if we have a netdev */ if (wdev->netdev) - flush_work(&wdev->disconnect_wk); + cancel_work_sync(&wdev->disconnect_wk); cfg80211_cqm_config_free(wdev); } @@ -1340,6 +1339,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, break; case NETDEV_GOING_DOWN: cfg80211_leave(rdev, wdev); + if (wdev->netdev) + cancel_work_sync(&wdev->disconnect_wk); break; case NETDEV_DOWN: cfg80211_update_iface_num(rdev, wdev->iftype, -1); -- 2.43.0