All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] gpio: fix gpio_chip add and remove
@ 2015-01-12 16:12 Johan Hovold
  2015-01-12 16:12 ` [PATCH 1/6] gpio: fix memory and reference leaks in gpiochip_add error path Johan Hovold
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold

This series fix a few issues with gpiochip_add and gpiochip_remove.

The gpio-chip removal paths have probably not been exercised much, and
there are further issues here that I'm working on fixing in order better
support hot-plugging of gpio chips. I believe these patches should go
into 3.19 meanwhile.

Johan


Johan Hovold (6):
  gpio: fix memory and reference leaks in gpiochip_add error path
  gpio: fix gpio-chip list corruption
  gpio: clean up gpiochip_add error handling
  gpio: fix memory leak and sleep-while-atomic
  gpio: fix sleep-while-atomic in gpiochip_remove
  gpio: unregister gpiochip device before removing it

 drivers/gpio/gpiolib.c | 58 ++++++++++++++++++++++++++------------------------
 1 file changed, 30 insertions(+), 28 deletions(-)

-- 
2.0.5

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

* [PATCH 1/6] gpio: fix memory and reference leaks in gpiochip_add error path
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
@ 2015-01-12 16:12 ` Johan Hovold
  2015-01-12 16:12 ` [PATCH 2/6] gpio: fix gpio-chip list corruption Johan Hovold
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold, stable

Memory allocated and references taken by of_gpiochip_add and
acpi_gpiochip_add were never released on errors in gpiochip_add (e.g.
failure to find free gpio range).

Fixes: 391c970c0dd1 ("of/gpio: add default of_xlate function if device
has a node pointer")
Fixes: 664e3e5ac64c ("gpio / ACPI: register to ACPI events
automatically")
Cc: stable <stable@vger.kernel.org>

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/gpio/gpiolib.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 487afe6f22fc..89c59f5f1924 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -277,6 +277,9 @@ int gpiochip_add(struct gpio_chip *chip)
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
+	if (status)
+		goto fail;
+
 #ifdef CONFIG_PINCTRL
 	INIT_LIST_HEAD(&chip->pin_ranges);
 #endif
@@ -284,12 +287,12 @@ int gpiochip_add(struct gpio_chip *chip)
 	of_gpiochip_add(chip);
 	acpi_gpiochip_add(chip);
 
-	if (status)
-		goto fail;
-
 	status = gpiochip_export(chip);
-	if (status)
+	if (status) {
+		acpi_gpiochip_remove(chip);
+		of_gpiochip_remove(chip);
 		goto fail;
+	}
 
 	pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,
 		chip->base, chip->base + chip->ngpio - 1,
-- 
2.0.5

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

* [PATCH 2/6] gpio: fix gpio-chip list corruption
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
  2015-01-12 16:12 ` [PATCH 1/6] gpio: fix memory and reference leaks in gpiochip_add error path Johan Hovold
@ 2015-01-12 16:12 ` Johan Hovold
  2015-01-12 16:12 ` [PATCH 3/6] gpio: clean up gpiochip_add error handling Johan Hovold
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold

Fix potential corruption of gpio-chip list due to failure to remove the
chip from the list before returning in gpiochip_add error path.

The chip could be long gone when the global list is next traversed,
something which could lead to a null-pointer dereference. In the best
case (chip not deallocated) we are just leaking the gpio range.

Fixes: 14e85c0e69d5 ("gpio: remove gpio_descs global array")
Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/gpio/gpiolib.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 89c59f5f1924..ac5944b4e4d8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -248,7 +248,8 @@ int gpiochip_add(struct gpio_chip *chip)
 		base = gpiochip_find_base(chip->ngpio);
 		if (base < 0) {
 			status = base;
-			goto unlock;
+			spin_unlock_irqrestore(&gpio_lock, flags);
+			goto err_free_descs;
 		}
 		chip->base = base;
 	}
@@ -288,11 +289,8 @@ int gpiochip_add(struct gpio_chip *chip)
 	acpi_gpiochip_add(chip);
 
 	status = gpiochip_export(chip);
-	if (status) {
-		acpi_gpiochip_remove(chip);
-		of_gpiochip_remove(chip);
-		goto fail;
-	}
+	if (status)
+		goto err_remove_chip;
 
 	pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,
 		chip->base, chip->base + chip->ngpio - 1,
@@ -300,9 +298,14 @@ int gpiochip_add(struct gpio_chip *chip)
 
 	return 0;
 
-unlock:
+err_remove_chip:
+	acpi_gpiochip_remove(chip);
+	of_gpiochip_remove(chip);
+	spin_lock_irqsave(&gpio_lock, flags);
+	list_del(&chip->list);
 	spin_unlock_irqrestore(&gpio_lock, flags);
 fail:
+err_free_descs:
 	kfree(descs);
 	chip->desc = NULL;
 
-- 
2.0.5

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

* [PATCH 3/6] gpio: clean up gpiochip_add error handling
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
  2015-01-12 16:12 ` [PATCH 1/6] gpio: fix memory and reference leaks in gpiochip_add error path Johan Hovold
  2015-01-12 16:12 ` [PATCH 2/6] gpio: fix gpio-chip list corruption Johan Hovold
@ 2015-01-12 16:12 ` Johan Hovold
  2015-01-12 16:12 ` [PATCH 4/6] gpio: fix memory leak and sleep-while-atomic Johan Hovold
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold

Clean up gpiochip_add error handling.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/gpio/gpiolib.c | 38 +++++++++++++++++---------------------
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index ac5944b4e4d8..4efb92ca3463 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -255,32 +255,29 @@ int gpiochip_add(struct gpio_chip *chip)
 	}
 
 	status = gpiochip_add_to_list(chip);
+	if (status) {
+		spin_unlock_irqrestore(&gpio_lock, flags);
+		goto err_free_descs;
+	}
 
-	if (status == 0) {
-		for (id = 0; id < chip->ngpio; id++) {
-			struct gpio_desc *desc = &descs[id];
-			desc->chip = chip;
-
-			/* REVISIT:  most hardware initializes GPIOs as
-			 * inputs (often with pullups enabled) so power
-			 * usage is minimized.  Linux code should set the
-			 * gpio direction first thing; but until it does,
-			 * and in case chip->get_direction is not set,
-			 * we may expose the wrong direction in sysfs.
-			 */
-			desc->flags = !chip->direction_input
-				? (1 << FLAG_IS_OUT)
-				: 0;
-		}
+	for (id = 0; id < chip->ngpio; id++) {
+		struct gpio_desc *desc = &descs[id];
+
+		desc->chip = chip;
+
+		/* REVISIT: most hardware initializes GPIOs as inputs (often
+		 * with pullups enabled) so power usage is minimized. Linux
+		 * code should set the gpio direction first thing; but until
+		 * it does, and in case chip->get_direction is not set, we may
+		 * expose the wrong direction in sysfs.
+		 */
+		desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
 	}
 
 	chip->desc = descs;
 
 	spin_unlock_irqrestore(&gpio_lock, flags);
 
-	if (status)
-		goto fail;
-
 #ifdef CONFIG_PINCTRL
 	INIT_LIST_HEAD(&chip->pin_ranges);
 #endif
@@ -304,10 +301,9 @@ err_remove_chip:
 	spin_lock_irqsave(&gpio_lock, flags);
 	list_del(&chip->list);
 	spin_unlock_irqrestore(&gpio_lock, flags);
-fail:
+	chip->desc = NULL;
 err_free_descs:
 	kfree(descs);
-	chip->desc = NULL;
 
 	/* failures here can mean systems won't boot... */
 	pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
-- 
2.0.5

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

* [PATCH 4/6] gpio: fix memory leak and sleep-while-atomic
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
                   ` (2 preceding siblings ...)
  2015-01-12 16:12 ` [PATCH 3/6] gpio: clean up gpiochip_add error handling Johan Hovold
@ 2015-01-12 16:12 ` Johan Hovold
  2015-01-12 16:12 ` [PATCH 5/6] gpio: fix sleep-while-atomic in gpiochip_remove Johan Hovold
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold, stable

Fix memory leak and sleep-while-atomic in gpiochip_remove.

The memory leak was introduced by afa82fab5e13 ("gpio / ACPI: Move event
handling registration to gpiolib irqchip helpers") that moved the
release of acpi interrupt resources to gpiochip_irqchip_remove, but by
then the resources are no longer accessible as the acpi_gpio_chip has
already been freed by acpi_gpiochip_remove.

Note that this also fixes a few potential sleep-while-atomics, which has
been around since 1425052097b5 ("gpio: add IRQ chip helpers in gpiolib")
when the call to gpiochip_irqchip_remove while holding a spinlock was
added (a couple of irq-domain paths can end up grabbing mutexes).

Fixes: afa82fab5e13 ("gpio / ACPI: Move event handling registration to
gpiolib irqchip helpers")
Fixes: 1425052097b5 ("gpio: add IRQ chip helpers in gpiolib")
Cc: stable <stable@vger.kernel.org>

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/gpio/gpiolib.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4efb92ca3463..0f8173051edc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -327,11 +327,12 @@ void gpiochip_remove(struct gpio_chip *chip)
 	unsigned long	flags;
 	unsigned	id;
 
+	gpiochip_irqchip_remove(chip);
+
 	acpi_gpiochip_remove(chip);
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
-	gpiochip_irqchip_remove(chip);
 	gpiochip_remove_pin_ranges(chip);
 	of_gpiochip_remove(chip);
 
-- 
2.0.5

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

* [PATCH 5/6] gpio: fix sleep-while-atomic in gpiochip_remove
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
                   ` (3 preceding siblings ...)
  2015-01-12 16:12 ` [PATCH 4/6] gpio: fix memory leak and sleep-while-atomic Johan Hovold
@ 2015-01-12 16:12 ` Johan Hovold
  2015-01-12 16:12 ` [PATCH 6/6] gpio: unregister gpiochip device before removing it Johan Hovold
  2015-01-14 13:27 ` [PATCH 0/6] gpio: fix gpio_chip add and remove Linus Walleij
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold, stable

Move direct and indirect calls to gpiochip_remove_pin_ranges outside of
spin lock as they can end up taking a mutex in pinctrl_remove_gpio_range.

Note that the pin ranges are already added outside of the lock.

Fixes: 9ef0d6f7628b ("gpiolib: call pin removal in chip removal function")
Fixes: f23f1516b675 ("gpiolib: provide provision to register pin ranges")
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/gpio/gpiolib.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 0f8173051edc..37f919dc2cb4 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -330,12 +330,10 @@ void gpiochip_remove(struct gpio_chip *chip)
 	gpiochip_irqchip_remove(chip);
 
 	acpi_gpiochip_remove(chip);
-
-	spin_lock_irqsave(&gpio_lock, flags);
-
 	gpiochip_remove_pin_ranges(chip);
 	of_gpiochip_remove(chip);
 
+	spin_lock_irqsave(&gpio_lock, flags);
 	for (id = 0; id < chip->ngpio; id++) {
 		if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
 			dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
-- 
2.0.5

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

* [PATCH 6/6] gpio: unregister gpiochip device before removing it
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
                   ` (4 preceding siblings ...)
  2015-01-12 16:12 ` [PATCH 5/6] gpio: fix sleep-while-atomic in gpiochip_remove Johan Hovold
@ 2015-01-12 16:12 ` Johan Hovold
  2015-01-14 13:27 ` [PATCH 0/6] gpio: fix gpio_chip add and remove Linus Walleij
  6 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2015-01-12 16:12 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Alexandre Courbot, linux-gpio, linux-kernel, Johan Hovold

Unregister gpiochip device (used to export information through sysfs)
before removing it internally. This way removal will reverse addition.

Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/gpio/gpiolib.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 37f919dc2cb4..568aa2b6bdb0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -327,6 +327,8 @@ void gpiochip_remove(struct gpio_chip *chip)
 	unsigned long	flags;
 	unsigned	id;
 
+	gpiochip_unexport(chip);
+
 	gpiochip_irqchip_remove(chip);
 
 	acpi_gpiochip_remove(chip);
@@ -343,7 +345,6 @@ void gpiochip_remove(struct gpio_chip *chip)
 
 	list_del(&chip->list);
 	spin_unlock_irqrestore(&gpio_lock, flags);
-	gpiochip_unexport(chip);
 
 	kfree(chip->desc);
 	chip->desc = NULL;
-- 
2.0.5

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

* Re: [PATCH 0/6] gpio: fix gpio_chip add and remove
  2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
                   ` (5 preceding siblings ...)
  2015-01-12 16:12 ` [PATCH 6/6] gpio: unregister gpiochip device before removing it Johan Hovold
@ 2015-01-14 13:27 ` Linus Walleij
  6 siblings, 0 replies; 8+ messages in thread
From: Linus Walleij @ 2015-01-14 13:27 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Alexandre Courbot, linux-gpio@vger.kernel.org,
	linux-kernel@vger.kernel.org

On Mon, Jan 12, 2015 at 5:12 PM, Johan Hovold <johan@kernel.org> wrote:

> This series fix a few issues with gpiochip_add and gpiochip_remove.
>
> The gpio-chip removal paths have probably not been exercised much, and
> there are further issues here that I'm working on fixing in order better
> support hot-plugging of gpio chips. I believe these patches should go
> into 3.19 meanwhile.

GOOD STUFF!
All six applied for fixes.

Yours,
Linus Walleij

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

end of thread, other threads:[~2015-01-14 13:27 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-12 16:12 [PATCH 0/6] gpio: fix gpio_chip add and remove Johan Hovold
2015-01-12 16:12 ` [PATCH 1/6] gpio: fix memory and reference leaks in gpiochip_add error path Johan Hovold
2015-01-12 16:12 ` [PATCH 2/6] gpio: fix gpio-chip list corruption Johan Hovold
2015-01-12 16:12 ` [PATCH 3/6] gpio: clean up gpiochip_add error handling Johan Hovold
2015-01-12 16:12 ` [PATCH 4/6] gpio: fix memory leak and sleep-while-atomic Johan Hovold
2015-01-12 16:12 ` [PATCH 5/6] gpio: fix sleep-while-atomic in gpiochip_remove Johan Hovold
2015-01-12 16:12 ` [PATCH 6/6] gpio: unregister gpiochip device before removing it Johan Hovold
2015-01-14 13:27 ` [PATCH 0/6] gpio: fix gpio_chip add and remove Linus Walleij

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.