The iwlwifi MLD driver registers .start_pmsr (iwl_mld_start_pmsr -> iwl_mld_ftm_start) but not .abort_pmsr. iwl_mld_ftm_start() stores the cfg80211 peer-measurement request in mld->ftm_initiator.req and the owning wdev in mld->ftm_initiator.req_wdev, and keeps both until a TOF range response completes the measurement. When the user space that started the FTM session closes its netlink socket (or the wdev goes down) while the measurement is still in flight, cfg80211_release_pmsr()/cfg80211_pmsr_wdev_down() schedule the abort work and cfg80211_pmsr_process_abort() runs: rdev_abort_pmsr(rdev, wdev, req); kfree(req); rdev_abort_pmsr() only calls the driver op when ops->abort_pmsr is set, so for MLD it is a no-op. The request is freed while mld->ftm_initiator.req still points at it; nothing clears the pointer. A subsequent TOF range response from the firmware reaches iwl_mld_handle_ftm_resp_notif(). The !mld->ftm_initiator.req guard does not catch this because the pointer is dangling, not NULL, so the handler dereferences the freed request (req->cookie, req->n_peers, req->peers[]) and passes it with req_wdev to cfg80211_pmsr_report()/cfg80211_pmsr_complete(); a use-after-free of the already freed request. Implement .abort_pmsr. iwl_mld_ftm_abort() checks that the aborted request is the active one, cancels the pending FTM notifications, resets the ftm_initiator state (clearing req and req_wdev), and sends TOF_RANGE_ABORT_CMD to the firmware so no further range responses are generated for the aborted request. Fixes: d1e879ec600f ("wifi: iwlwifi: add iwlmld sub-driver") Cc: stable@vger.kernel.org Assisted-by: Codex:gpt-5 Assisted-by: Claude:opus-4.8 Signed-off-by: Zhao Li --- .../intel/iwlwifi/mld/ftm-initiator.c | 22 +++++++++++++++++++ .../intel/iwlwifi/mld/ftm-initiator.h | 2 ++ .../net/wireless/intel/iwlwifi/mld/mac80211.c | 10 +++++++++ 3 files changed, 34 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c index 81df3fdfcbf56..b18e4fa9dedf1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c @@ -13,6 +13,7 @@ #include "constants.h" #include "fw/api/location.h" #include "ftm-initiator.h" +#include "hcmd.h" static void iwl_mld_ftm_cmd_common(struct iwl_mld *mld, struct ieee80211_vif *vif, @@ -282,6 +283,27 @@ static void iwl_mld_ftm_reset(struct iwl_mld *mld) sizeof(mld->ftm_initiator.responses)); } +void iwl_mld_ftm_abort(struct iwl_mld *mld, + struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_abort_cmd cmd = { + .request_id = req->cookie, + }; + + lockdep_assert_wiphy(mld->wiphy); + + if (req != mld->ftm_initiator.req) + return; + + iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_FTM_REQ, + (u8)req->cookie); + iwl_mld_ftm_reset(mld); + + if (iwl_mld_send_cmd_pdu(mld, WIDE_ID(LOCATION_GROUP, TOF_RANGE_ABORT_CMD), + &cmd)) + IWL_ERR(mld, "failed to abort FTM process\n"); +} + static int iwl_mld_ftm_range_resp_valid(struct iwl_mld *mld, u8 request_id, u8 num_of_aps) { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h index 3fab25a52508a..7b807605af503 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.h @@ -21,6 +21,8 @@ struct ftm_initiator_data { int iwl_mld_ftm_start(struct iwl_mld *mld, struct ieee80211_vif *vif, struct cfg80211_pmsr_request *req); +void iwl_mld_ftm_abort(struct iwl_mld *mld, + struct cfg80211_pmsr_request *req); void iwl_mld_handle_ftm_resp_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 17286b3341c02..614c55967fcca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -2853,6 +2853,15 @@ static int iwl_mld_start_pmsr(struct ieee80211_hw *hw, return iwl_mld_ftm_start(mld, vif, request); } +static void iwl_mld_abort_pmsr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + iwl_mld_ftm_abort(mld, request); +} + static enum ieee80211_neg_ttlm_res iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_neg_ttlm *neg_ttlm) @@ -2974,6 +2983,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .prep_add_interface = iwl_mld_prep_add_interface, .set_hw_timestamp = iwl_mld_set_hw_timestamp, .start_pmsr = iwl_mld_start_pmsr, + .abort_pmsr = iwl_mld_abort_pmsr, .can_neg_ttlm = iwl_mld_can_neg_ttlm, .start_nan = iwl_mld_start_nan, .stop_nan = iwl_mld_stop_nan, -- 2.50.1 (Apple Git-155)