diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-11-11 16:22:27 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-11-11 16:22:27 -0300 |
commit | 29f5b648fa0b31ad614c78468b9279e5fa96397a (patch) | |
tree | 385e76324c4e95e90b16889937e7c24e6f7d4f4a /drivers/gpio | |
parent | 1eae9639aac0f8de4d284f567ec722a822b52513 (diff) |
Linux-libre 4.8.7-gnupck-4.8.7-gnu
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 7 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 99 |
2 files changed, 91 insertions, 15 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index af514618d..14f2d9835 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -602,14 +602,17 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { int idx, i; unsigned int irq_flags; + int ret = -ENOENT; for (i = 0, idx = 0; idx <= index; i++) { struct acpi_gpio_info info; struct gpio_desc *desc; desc = acpi_get_gpiod_by_index(adev, NULL, i, &info); - if (IS_ERR(desc)) + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); break; + } if (info.gpioint && idx++ == index) { int irq = gpiod_to_irq(desc); @@ -628,7 +631,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) } } - return -ENOENT; + return ret; } EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 53ff25ac6..b2dee1024 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -21,6 +21,7 @@ #include <linux/uaccess.h> #include <linux/compat.h> #include <linux/anon_inodes.h> +#include <linux/file.h> #include <linux/kfifo.h> #include <linux/poll.h> #include <linux/timekeeping.h> @@ -331,6 +332,13 @@ struct linehandle_state { u32 numdescs; }; +#define GPIOHANDLE_REQUEST_VALID_FLAGS \ + (GPIOHANDLE_REQUEST_INPUT | \ + GPIOHANDLE_REQUEST_OUTPUT | \ + GPIOHANDLE_REQUEST_ACTIVE_LOW | \ + GPIOHANDLE_REQUEST_OPEN_DRAIN | \ + GPIOHANDLE_REQUEST_OPEN_SOURCE) + static long linehandle_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { @@ -342,6 +350,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { int val; + memset(&ghd, 0, sizeof(ghd)); + /* TODO: check if descriptors are really input */ for (i = 0; i < lh->numdescs; i++) { val = gpiod_get_value_cansleep(lh->descs[i]); @@ -412,6 +422,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) { struct gpiohandle_request handlereq; struct linehandle_state *lh; + struct file *file; int fd, i, ret; if (copy_from_user(&handlereq, ip, sizeof(handlereq))) @@ -442,6 +453,17 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) u32 lflags = handlereq.flags; struct gpio_desc *desc; + if (offset >= gdev->ngpio) { + ret = -EINVAL; + goto out_free_descs; + } + + /* Return an error if a unknown flag is set */ + if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) { + ret = -EINVAL; + goto out_free_descs; + } + desc = &gdev->descs[offset]; ret = gpiod_request(desc, lh->label); if (ret) @@ -477,26 +499,41 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) i--; lh->numdescs = handlereq.lines; - fd = anon_inode_getfd("gpio-linehandle", - &linehandle_fileops, - lh, - O_RDONLY | O_CLOEXEC); + fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); if (fd < 0) { ret = fd; goto out_free_descs; } + file = anon_inode_getfile("gpio-linehandle", + &linehandle_fileops, + lh, + O_RDONLY | O_CLOEXEC); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto out_put_unused_fd; + } + handlereq.fd = fd; if (copy_to_user(ip, &handlereq, sizeof(handlereq))) { - ret = -EFAULT; - goto out_free_descs; + /* + * fput() will trigger the release() callback, so do not go onto + * the regular error cleanup path here. + */ + fput(file); + put_unused_fd(fd); + return -EFAULT; } + fd_install(fd, file); + dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n", lh->numdescs); return 0; +out_put_unused_fd: + put_unused_fd(fd); out_free_descs: for (; i >= 0; i--) gpiod_free(lh->descs[i]); @@ -534,6 +571,10 @@ struct lineevent_state { struct mutex read_lock; }; +#define GPIOEVENT_REQUEST_VALID_FLAGS \ + (GPIOEVENT_REQUEST_RISING_EDGE | \ + GPIOEVENT_REQUEST_FALLING_EDGE) + static unsigned int lineevent_poll(struct file *filep, struct poll_table_struct *wait) { @@ -621,6 +662,8 @@ static long lineevent_ioctl(struct file *filep, unsigned int cmd, if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { int val; + memset(&ghd, 0, sizeof(ghd)); + val = gpiod_get_value_cansleep(le->desc); if (val < 0) return val; @@ -693,6 +736,7 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) struct gpioevent_request eventreq; struct lineevent_state *le; struct gpio_desc *desc; + struct file *file; u32 offset; u32 lflags; u32 eflags; @@ -724,6 +768,18 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) lflags = eventreq.handleflags; eflags = eventreq.eventflags; + if (offset >= gdev->ngpio) { + ret = -EINVAL; + goto out_free_label; + } + + /* Return an error if a unknown flag is set */ + if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) || + (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) { + ret = -EINVAL; + goto out_free_label; + } + /* This is just wrong: we don't look for events on output lines */ if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { ret = -EINVAL; @@ -775,23 +831,38 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (ret) goto out_free_desc; - fd = anon_inode_getfd("gpio-event", - &lineevent_fileops, - le, - O_RDONLY | O_CLOEXEC); + fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); if (fd < 0) { ret = fd; goto out_free_irq; } + file = anon_inode_getfile("gpio-event", + &lineevent_fileops, + le, + O_RDONLY | O_CLOEXEC); + if (IS_ERR(file)) { + ret = PTR_ERR(file); + goto out_put_unused_fd; + } + eventreq.fd = fd; if (copy_to_user(ip, &eventreq, sizeof(eventreq))) { - ret = -EFAULT; - goto out_free_irq; + /* + * fput() will trigger the release() callback, so do not go onto + * the regular error cleanup path here. + */ + fput(file); + put_unused_fd(fd); + return -EFAULT; } + fd_install(fd, file); + return 0; +out_put_unused_fd: + put_unused_fd(fd); out_free_irq: free_irq(le->irq, le); out_free_desc: @@ -821,6 +892,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (cmd == GPIO_GET_CHIPINFO_IOCTL) { struct gpiochip_info chipinfo; + memset(&chipinfo, 0, sizeof(chipinfo)); + strncpy(chipinfo.name, dev_name(&gdev->dev), sizeof(chipinfo.name)); chipinfo.name[sizeof(chipinfo.name)-1] = '\0'; @@ -837,7 +910,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; - if (lineinfo.line_offset > gdev->ngpio) + if (lineinfo.line_offset >= gdev->ngpio) return -EINVAL; desc = &gdev->descs[lineinfo.line_offset]; |