[PATCH 3/8] wifi: iwlwifi: mld: abort active PMSR requests

From: Zhao Li

Date: Wed Jul 08 2026 - 16:01:40 EST


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@xxxxxxxxxxxxxxx
Assisted-by: Codex:gpt-5
Assisted-by: Claude:opus-4.8
Signed-off-by: Zhao Li <enderaoelyther@xxxxxxxxx>
---
.../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)