]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: ath12k: fix out-of-bounds clear_bit in ath12k_mac_dp_peer_cleanup()
authorBaochen Qiang <baochen.qiang@oss.qualcomm.com>
Mon, 20 Jul 2026 06:43:22 +0000 (14:43 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Mon, 27 Jul 2026 15:00:41 +0000 (08:00 -0700)
ath12k_mac_dp_peer_cleanup() clears the ML peer ID slot on the
free_ml_peer_id_map bitmap by indexing it with dp_peer->peer_id. That is
wrong: dp_peer->peer_id for an MLO peer always carries the
ATH12K_PEER_ML_ID_VALID bit (BIT(13)), so clear_bit() is invoked with
index >= 0x2000, which is far outside the bitmap of ATH12K_MAX_MLO_PEERS
(256) bits and corrupts memory adjacent to ah->free_ml_peer_id_map. The
intended bitmap entry also never gets cleared, so subsequent
ath12k_peer_ml_alloc() calls eventually run out of IDs.

The ID without the VALID bit is what ath12k_peer_ml_alloc() returned and
is stored in ahsta->ml_peer_id. Use that instead.

While there, also reset ahsta->ml_peer_id to ATH12K_MLO_PEER_ID_INVALID so
the bitmap and ahsta->ml_peer_id stay in sync.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3

Fixes: ee16dcf573d5 ("wifi: ath12k: Define ath12k_dp_peer structure & APIs for create & delete")
Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Link: https://patch.msgid.link/20260720-ath12k-fw-allocated-ml-peer-id-v2-1-630632758a80@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/mac.c

index 51c4df32e71695585e52dafd0dd5c8912eaece80..aa82c8fccc4efa5b64998d4b3eb34823fda13294 100644 (file)
@@ -1287,8 +1287,11 @@ void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah)
        spin_lock_bh(&dp_hw->peer_lock);
        list_for_each_entry_safe(dp_peer, tmp, &dp_hw->dp_peers_list, list) {
                if (dp_peer->is_mlo) {
+                       struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(dp_peer->sta);
+
                        rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
-                       clear_bit(dp_peer->peer_id, ah->free_ml_peer_id_map);
+                       clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
+                       ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
                }
 
                list_move(&dp_peer->list, &peers);