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

Commit cc0de653 authored by Rajkumar Manoharan's avatar Rajkumar Manoharan Committed by John W. Linville
Browse files

ath9k_htc: Fix memory leak on WMI event handler



ath9k_wmi_ctrl_rx is racy with ath9k_wmi_tasklet on event notification
due to which the wmi_skb may be overwritten which leads to memory leak.

Signed-off-by: default avatarRajkumar Manoharan <rmanoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3a160a5b
Loading
Loading
Loading
Loading
+22 −50
Original line number Diff line number Diff line
@@ -124,55 +124,11 @@ void ath9k_wmi_tasklet(unsigned long data)
{
	struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
	struct ath_common *common = ath9k_hw_common(priv->ah);
	struct wmi_cmd_hdr *hdr;
	struct wmi_swba *swba_hdr;
	enum wmi_event_id event;
	struct sk_buff *skb;
	void *wmi_event;
	unsigned long flags;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
	__be32 txrate;
#endif

	spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
	skb = priv->wmi->wmi_skb;
	spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);

	hdr = (struct wmi_cmd_hdr *) skb->data;
	event = be16_to_cpu(hdr->command_id);
	wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
	ath_print(common, ATH_DBG_WMI, "SWBA Event received\n");

	ath_print(common, ATH_DBG_WMI,
		  "WMI Event: 0x%x\n", event);
	ath9k_htc_swba(priv, priv->wmi->beacon_pending);

	switch (event) {
	case WMI_TGT_RDY_EVENTID:
		break;
	case WMI_SWBA_EVENTID:
		swba_hdr = (struct wmi_swba *) wmi_event;
		ath9k_htc_swba(priv, swba_hdr->beacon_pending);
		break;
	case WMI_FATAL_EVENTID:
		break;
	case WMI_TXTO_EVENTID:
		break;
	case WMI_BMISS_EVENTID:
		break;
	case WMI_WLAN_TXCOMP_EVENTID:
		break;
	case WMI_DELBA_EVENTID:
		break;
	case WMI_TXRATE_EVENTID:
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
		txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
		priv->debug.txrate = be32_to_cpu(txrate);
#endif
		break;
	default:
		break;
	}

	kfree_skb(skb);
}

static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
@@ -191,6 +147,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
	struct wmi *wmi = (struct wmi *) priv;
	struct wmi_cmd_hdr *hdr;
	u16 cmd_id;
	void *wmi_event;
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
	__be32 txrate;
#endif

	if (unlikely(wmi->stopped))
		goto free_skb;
@@ -199,10 +159,22 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
	cmd_id = be16_to_cpu(hdr->command_id);

	if (cmd_id & 0x1000) {
		spin_lock(&wmi->wmi_lock);
		wmi->wmi_skb = skb;
		spin_unlock(&wmi->wmi_lock);
		wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
		switch (cmd_id) {
		case WMI_SWBA_EVENTID:
			wmi->beacon_pending = *(u8 *)wmi_event;
			tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
			break;
		case WMI_TXRATE_EVENTID:
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
			txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
			wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
#endif
			break;
		default:
			break;
		}
		kfree_skb(skb);
		return;
	}

+1 −5
Original line number Diff line number Diff line
@@ -31,10 +31,6 @@ struct wmi_cmd_hdr {
	__be16 seq_no;
} __packed;

struct wmi_swba {
	u8 beacon_pending;
} __packed;

enum wmi_cmd_id {
	WMI_ECHO_CMDID = 0x0001,
	WMI_ACCESS_MEMORY_CMDID,
@@ -104,7 +100,7 @@ struct wmi {
	u32 cmd_rsp_len;
	bool stopped;

	struct sk_buff *wmi_skb;
	u8 beacon_pending;
	spinlock_t wmi_lock;

	atomic_t mwrite_cnt;