wifi: ath9k: protect WMI command response buffer replacement with a lock
authorFedor Pchelkin <pchelkin@ispras.ru>
Tue, 25 Apr 2023 19:26:07 +0000 (22:26 +0300)
committerKalle Valo <quic_kvalo@quicinc.com>
Tue, 22 Aug 2023 13:35:17 +0000 (16:35 +0300)
If ath9k_wmi_cmd() has exited with a timeout, it is possible that during
next ath9k_wmi_cmd() call the wmi_rsp callback for previous wmi command
writes to new wmi->cmd_rsp_buf and makes a completion. This results in an
invalid ath9k_wmi_cmd() return value.

Move the replacement of WMI command response buffer and length under
wmi_lock. Note that last_seq_id value is updated there, too.

Thus, the buffer cannot be written to by a belated wmi_rsp callback
because that path is properly rejected by the last_seq_id check.

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.")
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
Acked-by: Toke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230425192607.18015-2-pchelkin@ispras.ru
drivers/net/wireless/ath/ath9k/wmi.c

index 04f363c..1476b42 100644 (file)
@@ -283,7 +283,8 @@ int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
 
 static int ath9k_wmi_cmd_issue(struct wmi *wmi,
                               struct sk_buff *skb,
-                              enum wmi_cmd_id cmd, u16 len)
+                              enum wmi_cmd_id cmd, u16 len,
+                              u8 *rsp_buf, u32 rsp_len)
 {
        struct wmi_cmd_hdr *hdr;
        unsigned long flags;
@@ -293,6 +294,11 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
        hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
 
        spin_lock_irqsave(&wmi->wmi_lock, flags);
+
+       /* record the rsp buffer and length */
+       wmi->cmd_rsp_buf = rsp_buf;
+       wmi->cmd_rsp_len = rsp_len;
+
        wmi->last_seq_id = wmi->tx_seq_id;
        spin_unlock_irqrestore(&wmi->wmi_lock, flags);
 
@@ -333,11 +339,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
                goto out;
        }
 
-       /* record the rsp buffer and length */
-       wmi->cmd_rsp_buf = rsp_buf;
-       wmi->cmd_rsp_len = rsp_len;
-
-       ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
+       ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len);
        if (ret)
                goto out;