* [PATCH 0/2] wifi: ath9k: fix WMI command response handling
@ 2026-10-20 15:24 Michail Andreas Michalopoulos
2026-10-20 15:24 ` [PATCH 1/2] wifi: ath9k: don't read past short WMI command responses Michail Andreas Michalopoulos
` (2 more replies)
0 siblings, 3 replies; 4+ 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
Both patches fix the ath9k_htc WMI command response path.
Patch 1 stops ath9k_wmi_rsp_callback() from copying bytes the device
did not send. It replaces the -EMSGSIZE approach that was reverted in
commit 90201351a862: short and empty responses still complete, and the
rest of the caller's buffer is zeroed.
Patch 2 stops responses from being accepted while no command is pending
(after completion, after a failed send, or with sequence number 0),
which could make a duplicate response write into the stack frame of a
caller that has already returned.
Testing: temporary KUnit tests (not included) drive the real
ath9k_wmi_ctrl_rx() and ath9k_wmi_cmd() against a fake HTC device in
x86_64 QEMU under KASAN, KMSAN, UBSAN and lockdep: short and empty
responses for all payload/buffer length combinations, duplicate and
late responses, failed sends, sequence number wrap, and a concurrent
stress test. Without the patches stale bytes reach the caller and KASAN
reports slab-use-after-free writes in ath9k_wmi_ctrl_rx(); with them the
tests pass with no reports. Builds cleanly with W=1 (GCC and Clang) and
sparse.
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.
The series applies on top of v7.3, which contains the revert; ath.git
does not have the revert yet.
Michail Andreas Michalopoulos (2):
wifi: ath9k: don't read past short WMI command responses
wifi: ath9k: drop WMI command responses when no command is pending
drivers/net/wireless/ath/ath9k/wmi.c | 47 +++++++++++++++++++++++-----
1 file changed, 40 insertions(+), 7 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [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; 4+ 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] 4+ 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; 4+ 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] 4+ 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
2 siblings, 0 replies; 4+ 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] 4+ messages in thread
end of thread, other threads:[~2026-10-20 22:46 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 0/2] wifi: ath9k: fix WMI command response handling Mehmet Fide
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®