diff options
author | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2020-04-15 10:23:59 +0200 |
---|---|---|
committer | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2020-04-23 17:55:27 +0200 |
commit | 4e1541593017d76cfa04bd666de8e4dbcfe3105d (patch) | |
tree | f57ab3f0ec6a8e32977145326d10243003cdb202 | |
parent | dc87f6dd058a648cd2a35e4aa04592dccdc9f0c2 (diff) | |
download | linux-4e1541593017d76cfa04bd666de8e4dbcfe3105d.tar.gz linux-4e1541593017d76cfa04bd666de8e4dbcfe3105d.tar.bz2 linux-4e1541593017d76cfa04bd666de8e4dbcfe3105d.zip |
gpiolib: improve the robustness of watch/unwatch ioctl()
This makes the new ioctl() a bit more robust - we now check if a line
is already being watched and return -EBUSY if the user-space tries to
start watching it again. Same for unwatch - return -EBUSY if user-space
tries to unwatch a line that's not being watched.
Fixes: 51c1064e82e7 ("gpiolib: add new ioctl() for monitoring changes in line info")
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/gpio/gpiolib.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 40f2d7f69be2..29f6abe84d2e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1227,6 +1227,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) void __user *ip = (void __user *)arg; struct gpio_desc *desc; __u32 offset; + int hwgpio; /* We fail any subsequent ioctl():s when the chip is gone */ if (!gc) @@ -1259,13 +1260,19 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); + hwgpio = gpio_chip_hwgpio(desc); + + if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL && + test_bit(hwgpio, priv->watched_lines)) + return -EBUSY; + gpio_desc_to_lineinfo(desc, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) - set_bit(gpio_chip_hwgpio(desc), priv->watched_lines); + set_bit(hwgpio, priv->watched_lines); return 0; } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { @@ -1280,7 +1287,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); - clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines); + hwgpio = gpio_chip_hwgpio(desc); + + if (!test_bit(hwgpio, priv->watched_lines)) + return -EBUSY; + + clear_bit(hwgpio, priv->watched_lines); return 0; } return -EINVAL; |