]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath11k: update channel list in reg notifier instead reg worker
authorWen Gong <quic_wgong@quicinc.com>
Fri, 17 Jan 2025 06:17:36 +0000 (14:17 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Thu, 6 Feb 2025 00:14:18 +0000 (16:14 -0800)
Currently when ath11k gets a new channel list, it will be processed
according to the following steps:
1. update new channel list to cfg80211 and queue reg_work.
2. cfg80211 handles new channel list during reg_work.
3. update cfg80211's handled channel list to firmware by
ath11k_reg_update_chan_list().

But ath11k will immediately execute step 3 after reg_work is just
queued. Since step 2 is asynchronous, cfg80211 may not have completed
handling the new channel list, which may leading to an out-of-bounds
write error:
BUG: KASAN: slab-out-of-bounds in ath11k_reg_update_chan_list
Call Trace:
    ath11k_reg_update_chan_list+0xbfe/0xfe0 [ath11k]
    kfree+0x109/0x3a0
    ath11k_regd_update+0x1cf/0x350 [ath11k]
    ath11k_regd_update_work+0x14/0x20 [ath11k]
    process_one_work+0xe35/0x14c0

Should ensure step 2 is completely done before executing step 3. Thus
Wen raised patch[1]. When flag NL80211_REGDOM_SET_BY_DRIVER is set,
cfg80211 will notify ath11k after step 2 is done.

So enable the flag NL80211_REGDOM_SET_BY_DRIVER then cfg80211 will
notify ath11k after step 2 is done. At this time, there will be no
KASAN bug during the execution of the step 3.

[1] https://patchwork.kernel.org/project/linux-wireless/patch/20230201065313.27203-1-quic_wgong@quicinc.com/

Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3

Fixes: f45cb6b29cd3 ("wifi: ath11k: avoid deadlock during regulatory update in ath11k_regd_update()")
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kang Yang <quic_kangyang@quicinc.com>
Reviewed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Link: https://patch.msgid.link/20250117061737.1921-2-quic_kangyang@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath11k/reg.c

index b0f289784dd3a2e1798c81b37a22d4fb0e69f183..7bfe47ad62a07f10fa6a277d54b8fd0568530b4b 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: BSD-3-Clause-Clear
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #include <linux/rtnetlink.h>
 
@@ -55,6 +55,19 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
        ath11k_dbg(ar->ab, ATH11K_DBG_REG,
                   "Regulatory Notification received for %s\n", wiphy_name(wiphy));
 
+       if (request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
+               ath11k_dbg(ar->ab, ATH11K_DBG_REG,
+                          "driver initiated regd update\n");
+               if (ar->state != ATH11K_STATE_ON)
+                       return;
+
+               ret = ath11k_reg_update_chan_list(ar, true);
+               if (ret)
+                       ath11k_warn(ar->ab, "failed to update channel list: %d\n", ret);
+
+               return;
+       }
+
        /* Currently supporting only General User Hints. Cell base user
         * hints to be handled later.
         * Hints from other sources like Core, Beacons are not expected for
@@ -293,12 +306,6 @@ int ath11k_regd_update(struct ath11k *ar)
        if (ret)
                goto err;
 
-       if (ar->state == ATH11K_STATE_ON) {
-               ret = ath11k_reg_update_chan_list(ar, true);
-               if (ret)
-                       goto err;
-       }
-
        return 0;
 err:
        ath11k_warn(ab, "failed to perform regd update : %d\n", ret);
@@ -977,6 +984,7 @@ void ath11k_regd_update_work(struct work_struct *work)
 void ath11k_reg_init(struct ath11k *ar)
 {
        ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
+       ar->hw->wiphy->flags |= WIPHY_FLAG_NOTIFY_REGDOM_BY_DRIVER;
        ar->hw->wiphy->reg_notifier = ath11k_reg_notifier;
 }