diff options
author | Johan Hovold <johan@kernel.org> | 2015-01-12 11:12:25 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-01-14 08:24:29 -0500 |
commit | 225fce83cb72e1bffb712a33ce47c210c770f8ab (patch) | |
tree | ff753de5fbb156b1990dc83782a195d8ec5cc081 | |
parent | 5539b3c938d64a60cb1fc442ac3ce9263d52de0c (diff) |
gpio: fix gpio-chip list corruption
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>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/gpio/gpiolib.c | 17 |
1 files 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) | |||
248 | base = gpiochip_find_base(chip->ngpio); | 248 | base = gpiochip_find_base(chip->ngpio); |
249 | if (base < 0) { | 249 | if (base < 0) { |
250 | status = base; | 250 | status = base; |
251 | goto unlock; | 251 | spin_unlock_irqrestore(&gpio_lock, flags); |
252 | goto err_free_descs; | ||
252 | } | 253 | } |
253 | chip->base = base; | 254 | chip->base = base; |
254 | } | 255 | } |
@@ -288,11 +289,8 @@ int gpiochip_add(struct gpio_chip *chip) | |||
288 | acpi_gpiochip_add(chip); | 289 | acpi_gpiochip_add(chip); |
289 | 290 | ||
290 | status = gpiochip_export(chip); | 291 | status = gpiochip_export(chip); |
291 | if (status) { | 292 | if (status) |
292 | acpi_gpiochip_remove(chip); | 293 | goto err_remove_chip; |
293 | of_gpiochip_remove(chip); | ||
294 | goto fail; | ||
295 | } | ||
296 | 294 | ||
297 | pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, | 295 | pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__, |
298 | chip->base, chip->base + chip->ngpio - 1, | 296 | chip->base, chip->base + chip->ngpio - 1, |
@@ -300,9 +298,14 @@ int gpiochip_add(struct gpio_chip *chip) | |||
300 | 298 | ||
301 | return 0; | 299 | return 0; |
302 | 300 | ||
303 | unlock: | 301 | err_remove_chip: |
302 | acpi_gpiochip_remove(chip); | ||
303 | of_gpiochip_remove(chip); | ||
304 | spin_lock_irqsave(&gpio_lock, flags); | ||
305 | list_del(&chip->list); | ||
304 | spin_unlock_irqrestore(&gpio_lock, flags); | 306 | spin_unlock_irqrestore(&gpio_lock, flags); |
305 | fail: | 307 | fail: |
308 | err_free_descs: | ||
306 | kfree(descs); | 309 | kfree(descs); |
307 | chip->desc = NULL; | 310 | chip->desc = NULL; |
308 | 311 | ||