]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.10.79/gpio-sysfs-fix-memory-leaks-and-device-hotplug.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.10.79 / gpio-sysfs-fix-memory-leaks-and-device-hotplug.patch
CommitLineData
b5be2e70
GKH
1From 483d821108791092798f5d230686868112927044 Mon Sep 17 00:00:00 2001
2From: Johan Hovold <johan@kernel.org>
3Date: Tue, 21 Apr 2015 17:42:09 +0200
4Subject: gpio: sysfs: fix memory leaks and device hotplug
5
6From: Johan Hovold <johan@kernel.org>
7
8commit 483d821108791092798f5d230686868112927044 upstream.
9
10Unregister GPIOs requested through sysfs at chip remove to avoid leaking
11the associated memory and sysfs entries.
12
13The stale sysfs entries prevented the gpio numbers from being exported
14when the gpio range was later reused (e.g. at device reconnect).
15
16This also fixes the related module-reference leak.
17
18Note that kernfs makes sure that any on-going sysfs operations finish
19before the class devices are unregistered and that further accesses
20fail.
21
22The chip exported flag is used to prevent gpiod exports during removal.
23This also makes it harder to trigger, but does not fix, the related race
24between gpiochip_remove and export_store, which is really a race with
25gpiod_request that needs to be addressed separately.
26
27Also note that this would prevent the crashes (e.g. NULL-dereferences)
28at reconnect that affects pre-3.18 kernels, as well as use-after-free on
29operations on open attribute files on pre-3.14 kernels (prior to
30kernfs).
31
32Fixes: d8f388d8dc8d ("gpio: sysfs interface")
33Signed-off-by: Johan Hovold <johan@kernel.org>
34Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
35Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
36
37---
38 drivers/gpio/gpiolib.c | 19 +++++++++++++++++++
39 1 file changed, 19 insertions(+)
40
41--- a/drivers/gpio/gpiolib.c
42+++ b/drivers/gpio/gpiolib.c
43@@ -752,6 +752,7 @@ static struct class gpio_class = {
44 */
45 static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
46 {
47+ struct gpio_chip *chip;
48 unsigned long flags;
49 int status;
50 const char *ioname = NULL;
51@@ -769,8 +770,16 @@ static int gpiod_export(struct gpio_desc
52 return -EINVAL;
53 }
54
55+ chip = desc->chip;
56+
57 mutex_lock(&sysfs_lock);
58
59+ /* check if chip is being removed */
60+ if (!chip || !chip->exported) {
61+ status = -ENODEV;
62+ goto fail_unlock;
63+ }
64+
65 spin_lock_irqsave(&gpio_lock, flags);
66 if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
67 test_bit(FLAG_EXPORT, &desc->flags)) {
68@@ -1040,6 +1049,8 @@ static void gpiochip_unexport(struct gpi
69 {
70 int status;
71 struct device *dev;
72+ struct gpio_desc *desc;
73+ unsigned int i;
74
75 mutex_lock(&sysfs_lock);
76 dev = class_find_device(&gpio_class, NULL, chip, match_export);
77@@ -1047,6 +1058,7 @@ static void gpiochip_unexport(struct gpi
78 sysfs_remove_group(&dev->kobj, &gpiochip_attr_group);
79 put_device(dev);
80 device_unregister(dev);
81+ /* prevent further gpiod exports */
82 chip->exported = 0;
83 status = 0;
84 } else
85@@ -1056,6 +1068,13 @@ static void gpiochip_unexport(struct gpi
86 if (status)
87 pr_debug("%s: chip %s status %d\n", __func__,
88 chip->label, status);
89+
90+ /* unregister gpiod class devices owned by sysfs */
91+ for (i = 0; i < chip->ngpio; i++) {
92+ desc = &chip->desc[i];
93+ if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
94+ gpiod_free(desc);
95+ }
96 }
97
98 static int __init gpiolib_sysfs_init(void)