]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: iwlwifi: mvm: validate TX_CMD response layout
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 15 Jul 2026 18:57:03 +0000 (21:57 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Thu, 16 Jul 2026 18:12:17 +0000 (21:12 +0300)
TX_CMD parsing uses frame_count to walk status entries and then
read the trailing SCD SSN. Make the minimum-length check follow
that exact runtime layout calculation before parsing the payload.

For new TX API, reject TX_CMD responses with frame_count != 1 and
warn/return in the aggregation handler to document that aggregated
accounting is expected via BA notifications.

Assisted-by: GitHubCopilot:gpt-5.3-codex
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260715215523.0474ee89bab9.I84f151aabecb8921b587da092f29f78c47128f0f@changeid
drivers/net/wireless/intel/iwlwifi/mvm/tx.c

index dc69c71faa76cae14fa2540e6cc5269097133c7f..d8b088e7c2504ac1dcf785e98ae0608a52620783 100644 (file)
@@ -1544,6 +1544,17 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm,
        return val & 0xFFF;
 }
 
+static inline size_t iwl_mvm_tx_resp_min_len(struct iwl_mvm *mvm,
+                                            struct iwl_tx_resp *tx_resp)
+{
+       struct agg_tx_status *agg_status =
+               iwl_mvm_get_agg_status(mvm, tx_resp);
+
+       /* The aggregate response ends with a trailing SCD SSN __le32 word. */
+       return (u8 *)(agg_status + tx_resp->frame_count) - (u8 *)tx_resp +
+               sizeof(__le32);
+}
+
 static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                                     struct iwl_rx_packet *pkt)
 {
@@ -1847,6 +1858,9 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
        int queue = SEQ_TO_QUEUE(sequence);
        struct ieee80211_sta *sta;
 
+       if (WARN_ON_ONCE(iwl_mvm_has_new_tx_api(mvm)))
+               return;
+
        if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE &&
                         (queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))
                return;
@@ -1881,6 +1895,26 @@ void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_tx_resp *tx_resp = (void *)pkt->data;
+       size_t min_len;
+
+       if (IWL_FW_CHECK(mvm, !tx_resp->frame_count,
+                        "invalid TX_CMD frame_count %u\n",
+                        tx_resp->frame_count))
+               return;
+
+       if (IWL_FW_CHECK(mvm,
+                        iwl_mvm_has_new_tx_api(mvm) &&
+                        tx_resp->frame_count != 1,
+                        "invalid TX_CMD frame_count %u for new TX API\n",
+                        tx_resp->frame_count))
+               return;
+
+       min_len = iwl_mvm_tx_resp_min_len(mvm, tx_resp);
+       if (IWL_FW_CHECK(mvm, iwl_rx_packet_payload_len(pkt) < min_len,
+                        "invalid TX_CMD len %u (frame_count %u, min %zu)\n",
+                        iwl_rx_packet_payload_len(pkt), tx_resp->frame_count,
+                        min_len))
+               return;
 
        if (tx_resp->frame_count == 1)
                iwl_mvm_rx_tx_cmd_single(mvm, pkt);