diff mbox

[1/6] wil6210: fix race conditions between TX send and completion

Message ID 1463426615-15523-2-git-send-email-qca_merez@qca.qualcomm.com (mailing list archive)
State Accepted
Commit 90eba92568b705ddf7dea9f25ed2693135ce3b9e
Delegated to: Kalle Valo
Headers show

Commit Message

Maya Erez May 16, 2016, 7:23 p.m. UTC
There are 2 possible race conditions, both are solved by addition of
memory barrier:
1. wil_tx_complete reads the swhead to determine if the vring is
empty. In case the swhead was updated before the descriptor update
was performed in __wil_tx_vring/__wil_tx_vring_tso, the completion
loop will not end and as the DU bit may still be set from a previous
run, this skb can be handled as completed before it was sent, which
will lead to double free of the same SKB.
2. __wil_tx_vring/__wil_tx_vring_tso calculate the number of available
descriptors according to the swtail. In case the swtail is updated
before memset of ctx to zero is completed, we can handle this
descriptor while later on ctx is zeroed.

Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>
---
 drivers/net/wireless/ath/wil6210/txrx.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Comments

Kalle Valo May 28, 2016, 8:19 a.m. UTC | #1
Maya Erez <qca_merez@qca.qualcomm.com> wrote:
> There are 2 possible race conditions, both are solved by addition of
> memory barrier:
> 1. wil_tx_complete reads the swhead to determine if the vring is
> empty. In case the swhead was updated before the descriptor update
> was performed in __wil_tx_vring/__wil_tx_vring_tso, the completion
> loop will not end and as the DU bit may still be set from a previous
> run, this skb can be handled as completed before it was sent, which
> will lead to double free of the same SKB.
> 2. __wil_tx_vring/__wil_tx_vring_tso calculate the number of available
> descriptors according to the swtail. In case the swtail is updated
> before memset of ctx to zero is completed, we can handle this
> descriptor while later on ctx is zeroed.
> 
> Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>

Thanks, 6 patches applied to ath.git:

eb26cff148f5 wil6210: fix race conditions between TX send and completion
ab6d7cc3eab4 wil6210: guarantee safe access to rx descriptors shared memory
34b8886e502a wil6210: protect wil_vring_fini_tx in parallel to tx completions
a1526f7eafa4 wil6210: fix dma mapping error cleanup in __wil_tx_vring_tso
e34dc6475a7b wil6210: add pm_notify handling
8fe2a5f9f9b5 wil6210: align wil log functions to wil_dbg_ratelimited implementation
diff mbox

Patch

diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index a4e4379..fa6ea24 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1551,6 +1551,13 @@  static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
 			     vring_index, used, used + descs_used);
 	}
 
+	/* Make sure to advance the head only after descriptor update is done.
+	 * This will prevent a race condition where the completion thread
+	 * will see the DU bit set from previous run and will handle the
+	 * skb before it was completed.
+	 */
+	wmb();
+
 	/* advance swhead */
 	wil_vring_advance_head(vring, descs_used);
 	wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead);
@@ -1691,6 +1698,13 @@  static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
 			     vring_index, used, used + nr_frags + 1);
 	}
 
+	/* Make sure to advance the head only after descriptor update is done.
+	 * This will prevent a race condition where the completion thread
+	 * will see the DU bit set from previous run and will handle the
+	 * skb before it was completed.
+	 */
+	wmb();
+
 	/* advance swhead */
 	wil_vring_advance_head(vring, nr_frags + 1);
 	wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead,
@@ -1914,6 +1928,12 @@  int wil_tx_complete(struct wil6210_priv *wil, int ringid)
 				wil_consume_skb(skb, d->dma.error == 0);
 			}
 			memset(ctx, 0, sizeof(*ctx));
+			/* Make sure the ctx is zeroed before updating the tail
+			 * to prevent a case where wil_tx_vring will see
+			 * this descriptor as used and handle it before ctx zero
+			 * is completed.
+			 */
+			wmb();
 			/* There is no need to touch HW descriptor:
 			 * - ststus bit TX_DMA_STATUS_DU is set by design,
 			 *   so hardware will not try to process this desc.,