From: Michail Andreas Michalopoulos <mike.michalo@gmail.com>
To: "Toke Høiland-Jørgensen" <toke@toke.dk>
Cc: Jeff Johnson <jeff.johnson@oss.qualcomm.com>,
Pengpeng Hou <pengpeng@iscas.ac.cn>,
Mehmet Fide <mehmet.fide@gmail.com>,
linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
Michail Andreas Michalopoulos <mike.michalo@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH 2/2] wifi: ath9k: drop WMI command responses when no command is pending
Date: Tue, 20 Oct 2026 17:24:12 +0200 [thread overview]
Message-ID: <20261020152412.95560-3-mike.michalo@gmail.com> (raw)
In-Reply-To: <20261020152412.95560-1-mike.michalo@gmail.com>
ath9k_wmi_ctrl_rx() accepts a command response whose sequence number
matches wmi->last_seq_id and copies it to wmi->cmd_rsp_buf, which
usually points into the stack frame of the ath9k_wmi_cmd() caller.
Only the timeout path clears last_seq_id, since
commit 8a2f35b98306 ("wifi: ath9k: Fix potential stack-out-of-bounds
write in ath9k_wmi_rsp_callback()"). After a normal completion or a
failed send the receive path stays armed, so a duplicate response from
a buggy or malicious device is written into a stack frame that is gone,
and its extra complete() makes the next command return before its own
response arrives. Sequence number 0, which means "nothing pending", is
also used for a command once tx_seq_id wraps.
Keep the receive path armed only while a command is pending: disarm it
once a response has been handled, on timeout and when sending fails,
drop responses while nothing is pending, never use sequence number 0,
and reinitialise the completion before each command is issued.
Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Michail Andreas Michalopoulos <mike.michalo@gmail.com>
---
drivers/net/wireless/ath/ath9k/wmi.c | 33 +++++++++++++++++++++++-----
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 76c8dfcc53..5fd20923ad 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -202,6 +202,16 @@ void ath9k_fatal_work(struct work_struct *work)
ath9k_htc_reset(priv);
}
+/* No command is pending: drop all responses until the next one is issued. */
+static void ath9k_wmi_cmd_disarm(struct wmi *wmi)
+{
+ lockdep_assert_held(&wmi->wmi_lock);
+
+ wmi->last_seq_id = 0;
+ wmi->cmd_rsp_buf = NULL;
+ wmi->cmd_rsp_len = 0;
+}
+
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
{
u32 len;
@@ -219,6 +229,9 @@ static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
memset(wmi->cmd_rsp_buf + len, 0, wmi->cmd_rsp_len - len);
}
+ /* The command is done; drop any further (duplicate) response. */
+ ath9k_wmi_cmd_disarm(wmi);
+
complete(&wmi->cmd_wait);
}
@@ -248,9 +261,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
return;
}
- /* Check if there has been a timeout. */
+ /* Only accept the response to the pending command, if any. */
spin_lock_irqsave(&wmi->wmi_lock, flags);
- if (be16_to_cpu(hdr->seq_no) != wmi->last_seq_id) {
+ if (!wmi->last_seq_id ||
+ be16_to_cpu(hdr->seq_no) != wmi->last_seq_id) {
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
goto free_skb;
}
@@ -303,7 +317,10 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
hdr = skb_push(skb, sizeof(struct wmi_cmd_hdr));
hdr->command_id = cpu_to_be16(cmd);
- hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
+ /* Sequence number 0 means "no command pending", so never send it. */
+ if (++wmi->tx_seq_id == 0)
+ wmi->tx_seq_id = 1;
+ hdr->seq_no = cpu_to_be16(wmi->tx_seq_id);
spin_lock_irqsave(&wmi->wmi_lock, flags);
@@ -311,6 +328,8 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
wmi->cmd_rsp_buf = rsp_buf;
wmi->cmd_rsp_len = rsp_len;
+ /* Drop any completion left over from an earlier response. */
+ reinit_completion(&wmi->cmd_wait);
wmi->last_seq_id = wmi->tx_seq_id;
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
@@ -352,15 +371,19 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
}
ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len);
- if (ret)
+ if (ret) {
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
+ ath9k_wmi_cmd_disarm(wmi);
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
goto out;
+ }
time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
if (!time_left) {
ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n",
wmi_cmd_to_name(cmd_id));
spin_lock_irqsave(&wmi->wmi_lock, flags);
- wmi->last_seq_id = 0;
+ ath9k_wmi_cmd_disarm(wmi);
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
mutex_unlock(&wmi->op_mutex);
return -ETIMEDOUT;
--
2.43.0
prev parent reply other threads:[~2026-10-20 15:24 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 15:24 [PATCH 0/2] wifi: ath9k: fix WMI command response handling Michail Andreas Michalopoulos
2026-10-20 15:24 ` [PATCH 1/2] wifi: ath9k: don't read past short WMI command responses Michail Andreas Michalopoulos
2026-10-20 15:24 ` Michail Andreas Michalopoulos [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261020152412.95560-3-mike.michalo@gmail.com \
--to=mike.michalo@gmail.com \
--cc=jeff.johnson@oss.qualcomm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=mehmet.fide@gmail.com \
--cc=pengpeng@iscas.ac.cn \
--cc=stable@vger.kernel.org \
--cc=toke@toke.dk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®