* [PATCH 1/2] wifi: ath9k: don't read past short WMI command responses
2026-10-20 15:24 [PATCH 0/2] wifi: ath9k: fix WMI command response handling Michail Andreas Michalopoulos
@ 2026-10-20 15:24 ` Michail Andreas Michalopoulos
2026-10-20 15:24 ` [PATCH 2/2] wifi: ath9k: drop WMI command responses when no command is pending Michail Andreas Michalopoulos
2026-10-20 22:46 ` [PATCH 0/2] wifi: ath9k: fix WMI command response handling Mehmet Fide
2 siblings, 0 replies; 5+ messages in thread
From: Michail Andreas Michalopoulos @ 2026-10-20 15:24 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: Jeff Johnson, Pengpeng Hou, Mehmet Fide, linux-wireless,
linux-kernel, Michail Andreas Michalopoulos, stable
ath9k_wmi_rsp_callback() copies cmd_rsp_len bytes from the response
without checking how many bytes the device sent. A short or empty
response makes it copy stale bytes from the uninitialised USB REG_IN
buffer into the caller's buffer, e.g. into the value returned by
ath9k_regread().
Commit 93ce8ea70451 ("wifi: ath9k: reject short WMI command responses")
failed such responses with -EMSGSIZE, but AR9271 firmware answers
commands that return nothing with an empty response, so that broke
normal operation and was reverted by commit 90201351a862 ("wifi: atk9k:
Revert "wifi: ath9k: reject short WMI command responses"").
Copy only the bytes that were received and zero the rest of the
caller's buffer instead. Empty responses keep completing successfully,
and callers no longer see bytes the device never sent.
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 | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 44e91815a1..76c8dfcc53 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -204,10 +204,20 @@ void ath9k_fatal_work(struct work_struct *work)
static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
{
+ u32 len;
+
skb_pull(skb, sizeof(struct wmi_cmd_hdr));
- if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0)
- memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len);
+ if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0) {
+ /*
+ * The firmware may send a shorter (even empty) response than
+ * the caller's buffer, e.g. for commands that return nothing.
+ * Copy only what was received and zero the rest.
+ */
+ len = min(skb->len, wmi->cmd_rsp_len);
+ memcpy(wmi->cmd_rsp_buf, skb->data, len);
+ memset(wmi->cmd_rsp_buf + len, 0, wmi->cmd_rsp_len - len);
+ }
complete(&wmi->cmd_wait);
}
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 2/2] wifi: ath9k: drop WMI command responses when no command is pending
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
2026-10-20 22:46 ` [PATCH 0/2] wifi: ath9k: fix WMI command response handling Mehmet Fide
2 siblings, 0 replies; 5+ messages in thread
From: Michail Andreas Michalopoulos @ 2026-10-20 15:24 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: Jeff Johnson, Pengpeng Hou, Mehmet Fide, linux-wireless,
linux-kernel, Michail Andreas Michalopoulos, stable
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
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 0/2] wifi: ath9k: fix WMI command response handling
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 ` [PATCH 2/2] wifi: ath9k: drop WMI command responses when no command is pending Michail Andreas Michalopoulos
@ 2026-10-20 22:46 ` Mehmet Fide
2026-10-20 23:19 ` mixalhs
2 siblings, 1 reply; 5+ messages in thread
From: Mehmet Fide @ 2026-10-20 22:46 UTC (permalink / raw)
To: Michail Andreas Michalopoulos
Cc: Toke Høiland-Jørgensen, Jeff Johnson, Pengpeng Hou,
linux-wireless, linux-kernel, mehmet.fide
Hi Michail,
On 2026-10-20, Michail Andreas Michalopoulos wrote:
> I don't have access to an ath9k_htc device, so this was not tested on
> hardware. Mehmet, if you could give it a try on your AR9271 that would
> be much appreciated.
Tested on an AR9271 with firmware 1.4 as an AP, on 6.12.113 with the
revert of 93ce8ea70451.
The AP comes up and works; the empty responses the firmware sends for
most commands complete as before. A test build that delivered responses
twice had every duplicate dropped, and with tx_seq_id started just below
the wrap, 0 was never sent. hostapd restarts, module reloads, USB
unbind/bind and a 30 minute soak with traffic ran without a WMI timeout
or a kernel warning.
Tested-by: Mehmet Fide <mehmet.fide@screeningeagle.com>
Thanks,
Mehmet
^ permalink raw reply [flat|nested] 5+ messages in thread