Fix a stack-out-of-bounds write that occurs in a WMI response callback function that is called after a timeout occurs in ath9k_wmi_cmd(). The callback writes to wmi->cmd_rsp_buf, a stack-allocated buffer that could no longer be valid when a timeout occurs. Checking seq_no is insufficient as the bug can occur between the timeout and the next WMI command. Add wmi->timedout to check whether a timeout occurred. Found by a modified version of syzkaller. BUG: KASAN: stack-out-of-bounds in ath9k_wmi_ctrl_rx Write of size 4 Call Trace: memcpy ath9k_wmi_ctrl_rx ath9k_htc_rx_msg ath9k_hif_usb_reg_in_cb __usb_hcd_giveback_urb usb_hcd_giveback_urb dummy_timer call_timer_fn run_timer_softirq __do_softirq irq_exit_rcu sysvec_apic_timer_interrupt Signed-off-by: Minsuk Kang <linuxlovemin@xxxxxxxxxxxx> --- drivers/net/wireless/ath/ath9k/wmi.c | 5 ++++- drivers/net/wireless/ath/ath9k/wmi.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index f315c54bd3ac..f46cbecc12e3 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -234,7 +234,8 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, /* Check if there has been a timeout. */ spin_lock_irqsave(&wmi->wmi_lock, flags); - if (be16_to_cpu(hdr->seq_no) != wmi->last_seq_id) { + if (be16_to_cpu(hdr->seq_no) != wmi->last_seq_id || + wmi->timedout) { spin_unlock_irqrestore(&wmi->wmi_lock, flags); goto free_skb; } @@ -290,6 +291,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, spin_lock_irqsave(&wmi->wmi_lock, flags); wmi->last_seq_id = wmi->tx_seq_id; + wmi->timedout = false; spin_unlock_irqrestore(&wmi->wmi_lock, flags); return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid); @@ -341,6 +343,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, if (!time_left) { ath_dbg(common, WMI, "Timeout waiting for WMI command: %s\n", wmi_cmd_to_name(cmd_id)); + wmi->timedout = true; mutex_unlock(&wmi->op_mutex); return -ETIMEDOUT; } diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 5c3b710b8f31..2cdfea4da906 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -158,6 +158,7 @@ struct wmi { u8 *cmd_rsp_buf; u32 cmd_rsp_len; bool stopped; + bool timedout; struct list_head pending_tx_events; spinlock_t event_lock; -- 2.25.1