Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f6f00bc authored by Fedor Pchelkin's avatar Fedor Pchelkin Committed by Greg Kroah-Hartman
Browse files

wifi: ath9k: protect WMI command response buffer replacement with a lock



[ Upstream commit 454994cfa9e4c18b6df9f78b60db8eadc20a6c25 ]

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: fb9987d0 ("ath9k_htc: Support for AR9271 chipset.")
Signed-off-by: default avatarFedor Pchelkin <pchelkin@ispras.ru>
Acked-by: default avatarToke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20230425192607.18015-2-pchelkin@ispras.ru


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent ff703b5f
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -280,7 +280,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;
@@ -290,6 +291,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);

@@ -330,11 +336,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;