mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
wifi: ath9k: protect WMI command response buffer replacement with a lock
[ Upstream commit454994cfa9] 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:fb9987d0f7("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 Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
8ba31f946a
commit
4c340bfddc
@@ -283,7 +283,8 @@ int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
|
|||||||
|
|
||||||
static int ath9k_wmi_cmd_issue(struct wmi *wmi,
|
static int ath9k_wmi_cmd_issue(struct wmi *wmi,
|
||||||
struct sk_buff *skb,
|
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;
|
struct wmi_cmd_hdr *hdr;
|
||||||
unsigned long flags;
|
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);
|
hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
|
||||||
|
|
||||||
spin_lock_irqsave(&wmi->wmi_lock, flags);
|
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;
|
wmi->last_seq_id = wmi->tx_seq_id;
|
||||||
spin_unlock_irqrestore(&wmi->wmi_lock, flags);
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* record the rsp buffer and length */
|
ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len, rsp_buf, rsp_len);
|
||||||
wmi->cmd_rsp_buf = rsp_buf;
|
|
||||||
wmi->cmd_rsp_len = rsp_len;
|
|
||||||
|
|
||||||
ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user