All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] regulator: core: avoid memory access after freeing it
@ 2012-11-06 10:34 Laxman Dewangan
  2012-11-06 11:12 ` Charles Keepax
  0 siblings, 1 reply; 8+ messages in thread
From: Laxman Dewangan @ 2012-11-06 10:34 UTC (permalink / raw)
  To: broonie, lrg; +Cc: linux-kernel, Laxman Dewangan, Charles Keepax

When regulator_register() failed due to non availability of
supply then it exits through cleanup path. In this case it
checks for supply and if it is valid then unregister the supply.

The change done by Charles Keepax:
	regulator: core: Move regulator release to avoid deadlock

puts the release of supply regualtor after device_unregister().
The device_unregister() frees the rdev and hence accessing rdev
member pointer after this calls gives incorrect pointer and cause
the system to crash.

Adding the locked version of regulator_put() as __regulator_put_locked()
so that it can be called in locked context also to avoid the deadlock
to address the above issue.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Cc: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
---
 drivers/regulator/core.c |   30 ++++++++++++++++++------------
 1 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index b4a425a..59280b6 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1382,23 +1382,16 @@ struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
 EXPORT_SYMBOL_GPL(regulator_get_exclusive);
 
 /**
- * regulator_put - "free" the regulator source
- * @regulator: regulator source
- *
- * Note: drivers must ensure that all regulator_enable calls made on this
- * regulator source are balanced by regulator_disable calls prior to calling
- * this function.
+ * Locked version of regulator_put
  */
-void regulator_put(struct regulator *regulator)
+static void __regulator_put_locked(struct regulator *regulator)
 {
 	struct regulator_dev *rdev;
 
 	if (regulator == NULL || IS_ERR(regulator))
 		return;
 
-	mutex_lock(&regulator_list_mutex);
 	rdev = regulator->rdev;
-
 	debugfs_remove_recursive(regulator->debugfs);
 
 	/* remove any sysfs entries */
@@ -1412,6 +1405,20 @@ void regulator_put(struct regulator *regulator)
 	rdev->exclusive = 0;
 
 	module_put(rdev->owner);
+}
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator)
+{
+	mutex_lock(&regulator_list_mutex);
+	__regulator_put_locked(regulator);
 	mutex_unlock(&regulator_list_mutex);
 }
 EXPORT_SYMBOL_GPL(regulator_put);
@@ -3453,11 +3460,10 @@ scrub:
 		gpio_free(rdev->ena_gpio);
 	kfree(rdev->constraints);
 wash:
+	if (rdev->supply)
+		__regulator_put_locked(rdev->supply);
 	device_unregister(&rdev->dev);
-
 	mutex_unlock(&regulator_list_mutex);
-	if (rdev->supply)
-		regulator_put(rdev->supply);
 
 	/* device core frees rdev */
 	rdev = ERR_PTR(ret);
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] regulator: core: avoid memory access after freeing it
  2012-11-06 10:34 [PATCH] regulator: core: avoid memory access after freeing it Laxman Dewangan
@ 2012-11-06 11:12 ` Charles Keepax
  2012-11-06 11:31   ` Mark Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Charles Keepax @ 2012-11-06 11:12 UTC (permalink / raw)
  To: Laxman Dewangan; +Cc: broonie, lrg, linux-kernel

On Tue, Nov 06, 2012 at 04:04:09PM +0530, Laxman Dewangan wrote:
> When regulator_register() failed due to non availability of
>  	mutex_unlock(&regulator_list_mutex);
...
>  }
>  EXPORT_SYMBOL_GPL(regulator_put);
> @@ -3453,11 +3460,10 @@ scrub:
>  		gpio_free(rdev->ena_gpio);
>  	kfree(rdev->constraints);
>  wash:
> +	if (rdev->supply)
> +		__regulator_put_locked(rdev->supply);
>  	device_unregister(&rdev->dev);
> -
>  	mutex_unlock(&regulator_list_mutex);
> -	if (rdev->supply)
> -		regulator_put(rdev->supply);
>  
>  	/* device core frees rdev */
>  	rdev = ERR_PTR(ret);

Here would it not make sense to go slightly further and basically
revert my original change. This feels sensible as it keeps it at
only one location where the mutex is unlocked and removes the
second exit point I added. This would effectively make the code
look like:

scrub:
	if (rdev->supply)
		__regulator_put_locked(rdev->supply);
	if (rdev->ena_gpio)
		gpio_free(rdev->ena_gpio);
	kfree(rdev->constraints);
	device_unregister(&rdev->dev);
	/* device core frees rdev */
	rdev = ERR_PTR(ret);
	goto out;

Otherwise the change looks great to me.

> -- 
> 1.7.1.1
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] regulator: core: avoid memory access after freeing it
  2012-11-06 11:12 ` Charles Keepax
@ 2012-11-06 11:31   ` Mark Brown
  2012-11-13 16:30     ` [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock Charles Keepax
  0 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2012-11-06 11:31 UTC (permalink / raw)
  To: Charles Keepax; +Cc: Laxman Dewangan, lrg, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 561 bytes --]

On Tue, Nov 06, 2012 at 11:12:56AM +0000, Charles Keepax wrote:

> Here would it not make sense to go slightly further and basically
> revert my original change. This feels sensible as it keeps it at
> only one location where the mutex is unlocked and removes the
> second exit point I added. This would effectively make the code
> look like:

Given the bug that was reported with your original change and the lack
of any fix I'm actually just going to discard it anyway, just didn't get
around to it yet.

A single exit path would be simpler and hence better.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock
  2012-11-06 11:31   ` Mark Brown
@ 2012-11-13 16:30     ` Charles Keepax
  2012-11-13 17:16       ` Laxman Dewangan
  2012-11-13 23:25       ` Mark Brown
  0 siblings, 2 replies; 8+ messages in thread
From: Charles Keepax @ 2012-11-13 16:30 UTC (permalink / raw)
  To: Mark Brown, lrg, ldewangan; +Cc: linux-kernel

When regulator_register fails and exits through the scrub path the
regulator_put function was called whilst holding the
regulator_list_mutex, which is also locked from regulator_put, causing
deadlock.

This patch adds a locked version of the regulator_put function which can
be safely called whilst holding the mutex, replacing the aforementioned
call.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Cc: Laxman Dewangan <ldewangan@nvidia.com>
---

I hope this isn't bad etiquette but I took the liberaty of fixing up
the patch as per the comments and taking into account the removal of
my original patch. Apologies if this is not the done thing, do let
me know if you would rather submit a version yourself but I
thought best to address the issue and get a fix in.

 drivers/regulator/core.c |   26 +++++++++++++++++---------
 1 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 5c4829c..854d18f 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1382,21 +1382,15 @@ struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
 EXPORT_SYMBOL_GPL(regulator_get_exclusive);
 
 /**
- * regulator_put - "free" the regulator source
- * @regulator: regulator source
- *
- * Note: drivers must ensure that all regulator_enable calls made on this
- * regulator source are balanced by regulator_disable calls prior to calling
- * this function.
+ * Locked version of regulator_put
  */
-void regulator_put(struct regulator *regulator)
+static void __regulator_put_locked(struct regulator *regulator)
 {
 	struct regulator_dev *rdev;
 
 	if (regulator == NULL || IS_ERR(regulator))
 		return;
 
-	mutex_lock(&regulator_list_mutex);
 	rdev = regulator->rdev;
 
 	debugfs_remove_recursive(regulator->debugfs);
@@ -1412,6 +1406,20 @@ void regulator_put(struct regulator *regulator)
 	rdev->exclusive = 0;
 
 	module_put(rdev->owner);
+}
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator)
+{
+	mutex_lock(&regulator_list_mutex);
+	__regulator_put_locked(regulator);
 	mutex_unlock(&regulator_list_mutex);
 }
 EXPORT_SYMBOL_GPL(regulator_put);
@@ -3445,7 +3453,7 @@ unset_supplies:
 
 scrub:
 	if (rdev->supply)
-		regulator_put(rdev->supply);
+		__regulator_put_locked(rdev->supply);
 	if (rdev->ena_gpio)
 		gpio_free(rdev->ena_gpio);
 	kfree(rdev->constraints);
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock
  2012-11-13 16:30     ` [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock Charles Keepax
@ 2012-11-13 17:16       ` Laxman Dewangan
  2012-11-13 23:25       ` Mark Brown
  1 sibling, 0 replies; 8+ messages in thread
From: Laxman Dewangan @ 2012-11-13 17:16 UTC (permalink / raw)
  To: Charles Keepax; +Cc: Mark Brown, lrg, linux-kernel

On Tuesday 13 November 2012 10:00 PM, Charles Keepax wrote:
> When regulator_register fails and exits through the scrub path the
> regulator_put function was called whilst holding the
> regulator_list_mutex, which is also locked from regulator_put, causing
> deadlock.
>
> This patch adds a locked version of the regulator_put function which can
> be safely called whilst holding the mutex, replacing the aforementioned
> call.
>
> Signed-off-by: Charles Keepax<ckeepax@opensource.wolfsonmicro.com>
> Cc: Laxman Dewangan<ldewangan@nvidia.com>
> ---
>
> I hope this isn't bad etiquette but I took the liberaty of fixing up
> the patch as per the comments and taking into account the removal of
> my original patch. Apologies if this is not the done thing, do let
> me know if you would rather submit a version yourself but I
> thought best to address the issue and get a fix in.

This looks fine.
Acked-by: Laxman Dewangan <ldewangan@nvidia.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock
  2012-11-13 16:30     ` [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock Charles Keepax
  2012-11-13 17:16       ` Laxman Dewangan
@ 2012-11-13 23:25       ` Mark Brown
  2012-11-14  9:39         ` [PATCH v2] regulator: core: Avoid deadlock when regulator_register fails Charles Keepax
  1 sibling, 1 reply; 8+ messages in thread
From: Mark Brown @ 2012-11-13 23:25 UTC (permalink / raw)
  To: Charles Keepax; +Cc: lrg, ldewangan, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 500 bytes --]

On Tue, Nov 13, 2012 at 04:30:40PM +0000, Charles Keepax wrote:

> -void regulator_put(struct regulator *regulator)
> +static void __regulator_put_locked(struct regulator *regulator)

Please do follow the coding style of the rest of the code; nothing else
is using __ for private functions.

Please also clarify the changelog - you're not adding a new API here,
you're fiddling about with the internals.  Obviously regulator_put() is
always locked, you're just rearranging code inside the core here.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] regulator: core: Avoid deadlock when regulator_register fails
  2012-11-13 23:25       ` Mark Brown
@ 2012-11-14  9:39         ` Charles Keepax
  2012-11-14 10:01           ` Mark Brown
  0 siblings, 1 reply; 8+ messages in thread
From: Charles Keepax @ 2012-11-14  9:39 UTC (permalink / raw)
  To: Mark Brown; +Cc: lrg, ldewangan, linux-kernel

When regulator_register fails and exits through the scrub path the
regulator_put function was called whilst holding the
regulator_list_mutex, causing deadlock.

This patch adds a private version of the regulator_put function which
can be safely called whilst holding the mutex, replacing the
aforementioned call.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Cc: Laxman Dewangan <ldewangan@nvidia.com>
---
 drivers/regulator/core.c |   28 +++++++++++++++++-----------
 1 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 1a35251..390e173 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1381,22 +1381,14 @@ struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL_GPL(regulator_get_exclusive);
 
-/**
- * regulator_put - "free" the regulator source
- * @regulator: regulator source
- *
- * Note: drivers must ensure that all regulator_enable calls made on this
- * regulator source are balanced by regulator_disable calls prior to calling
- * this function.
- */
-void regulator_put(struct regulator *regulator)
+/* Locks held by regulator_put() */
+static void _regulator_put(struct regulator *regulator)
 {
 	struct regulator_dev *rdev;
 
 	if (regulator == NULL || IS_ERR(regulator))
 		return;
 
-	mutex_lock(&regulator_list_mutex);
 	rdev = regulator->rdev;
 
 	debugfs_remove_recursive(regulator->debugfs);
@@ -1412,6 +1404,20 @@ void regulator_put(struct regulator *regulator)
 	rdev->exclusive = 0;
 
 	module_put(rdev->owner);
+}
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator)
+{
+	mutex_lock(&regulator_list_mutex);
+	_regulator_put(regulator);
 	mutex_unlock(&regulator_list_mutex);
 }
 EXPORT_SYMBOL_GPL(regulator_put);
@@ -3450,7 +3456,7 @@ unset_supplies:
 
 scrub:
 	if (rdev->supply)
-		regulator_put(rdev->supply);
+		_regulator_put(rdev->supply);
 	if (rdev->ena_gpio)
 		gpio_free(rdev->ena_gpio);
 	kfree(rdev->constraints);
-- 
1.7.2.5


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2] regulator: core: Avoid deadlock when regulator_register fails
  2012-11-14  9:39         ` [PATCH v2] regulator: core: Avoid deadlock when regulator_register fails Charles Keepax
@ 2012-11-14 10:01           ` Mark Brown
  0 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2012-11-14 10:01 UTC (permalink / raw)
  To: Charles Keepax; +Cc: lrg, ldewangan, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 409 bytes --]

On Wed, Nov 14, 2012 at 09:39:31AM +0000, Charles Keepax wrote:
> When regulator_register fails and exits through the scrub path the
> regulator_put function was called whilst holding the
> regulator_list_mutex, causing deadlock.

Applied, thanks.

> Cc: Laxman Dewangan <ldewangan@nvidia.com>

Please avoid doing this.  I know a lot of people do but it makes for
hand editing of the commit log to remove it.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-11-14 10:01 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-06 10:34 [PATCH] regulator: core: avoid memory access after freeing it Laxman Dewangan
2012-11-06 11:12 ` Charles Keepax
2012-11-06 11:31   ` Mark Brown
2012-11-13 16:30     ` [PATCH] regulator: core: Add locked version of regulator_put to avoid deadlock Charles Keepax
2012-11-13 17:16       ` Laxman Dewangan
2012-11-13 23:25       ` Mark Brown
2012-11-14  9:39         ` [PATCH v2] regulator: core: Avoid deadlock when regulator_register fails Charles Keepax
2012-11-14 10:01           ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.