lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 14 May 2010 14:45:03 -0700
From:	Inaky Perez-Gonzalez <inaky@...ux.intel.com>
To:	netdev@...r.kernel.org, wimax@...uxwimax.org
Cc:	Cindy H Kao <cindy.h.kao@...el.com>
Subject: [patch 2.6.35 04/25] wimax/i2400m: fix the race condition for accessing TX queue

From: Cindy H Kao <cindy.h.kao@...el.com>

The race condition happens when the TX queue is accessed by
the TX work while the same TX queue is being destroyed because
a bus reset is triggered either by debugfs entry or simply
by failing waking up the device from WiMAX IDLE mode.

This fix is to prevent the TX queue from being accessed by
multiple threads

Signed-off-by: Cindy H Kao <cindy.h.kao@...el.com>
---
 drivers/net/wimax/i2400m/i2400m-sdio.h |    5 ++++-
 drivers/net/wimax/i2400m/sdio-tx.c     |   31 ++++++++++++++++++++++++-------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index b9c4bed..360d4fb 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -99,7 +99,10 @@ enum {
  *
  * @tx_workqueue: workqeueue used for data TX; we don't use the
  *     system's workqueue as that might cause deadlocks with code in
- *     the bus-generic driver.
+ *     the bus-generic driver. The read/write operation to the queue
+ *     is protected with spinlock (tx_lock in struct i2400m) to avoid
+ *     the queue being destroyed in the middle of a the queue read/write
+ *     operation.
  *
  * @debugfs_dentry: dentry for the SDIO specific debugfs files
  *
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c
index de66d06..412b6a8 100644
--- a/drivers/net/wimax/i2400m/sdio-tx.c
+++ b/drivers/net/wimax/i2400m/sdio-tx.c
@@ -114,13 +114,17 @@ void i2400ms_bus_tx_kick(struct i2400m *i2400m)
 {
 	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
 	struct device *dev = &i2400ms->func->dev;
+	unsigned long flags;
 
 	d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
 
 	/* schedule tx work, this is because tx may block, therefore
 	 * it has to run in a thread context.
 	 */
-	queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+	spin_lock_irqsave(&i2400m->tx_lock, flags);
+	if (i2400ms->tx_workqueue != NULL)
+		queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+	spin_unlock_irqrestore(&i2400m->tx_lock, flags);
 
 	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
 }
@@ -130,27 +134,40 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
 	int result;
 	struct device *dev = &i2400ms->func->dev;
 	struct i2400m *i2400m = &i2400ms->i2400m;
+	struct workqueue_struct *tx_workqueue;
+	unsigned long flags;
 
 	d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
 
 	INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit);
 	snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name),
 		 "%s-tx", i2400m->wimax_dev.name);
-	i2400ms->tx_workqueue =
+	tx_workqueue =
 		create_singlethread_workqueue(i2400ms->tx_wq_name);
-	if (NULL == i2400ms->tx_workqueue) {
+	if (tx_workqueue == NULL) {
 		dev_err(dev, "TX: failed to create workqueue\n");
 		result = -ENOMEM;
 	} else
 		result = 0;
+	spin_lock_irqsave(&i2400m->tx_lock, flags);
+	i2400ms->tx_workqueue = tx_workqueue;
+	spin_unlock_irqrestore(&i2400m->tx_lock, flags);
 	d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
 	return result;
 }
 
 void i2400ms_tx_release(struct i2400ms *i2400ms)
 {
-	if (i2400ms->tx_workqueue) {
-		destroy_workqueue(i2400ms->tx_workqueue);
-		i2400ms->tx_workqueue = NULL;
-	}
+	struct i2400m *i2400m = &i2400ms->i2400m;
+	struct workqueue_struct *tx_workqueue;
+	unsigned long flags;
+
+	tx_workqueue = i2400ms->tx_workqueue;
+
+	spin_lock_irqsave(&i2400m->tx_lock, flags);
+	i2400ms->tx_workqueue = NULL;
+	spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+	if (tx_workqueue)
+		destroy_workqueue(tx_workqueue);
 }
-- 
1.6.6.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ