diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-24 21:19:07 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-24 21:19:07 -0700 |
commit | 1ce5bdb8312b6e9629029340063ea1e5cfac435d (patch) | |
tree | c47706ca6b30ff50ec204e5abfb5ee22dc841e48 /drivers/gpio/gpiolib.c | |
parent | aa34e07e457ed13b44d680b5b605e3e5a585f611 (diff) | |
parent | d71cf15b865bdd45925f7b094d169aaabd705145 (diff) |
Merge tag 'gpio-v4.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO fixes from Linus Walleij:
"Here is a set of GPIO fixes for the v4.9 kernel series:
- Fix up off-by one and line offset validation, info leak to
userspace, and reject invalid flags. Those are especially valuable
hardening patches from Lars-Peter Clausen, all tagged for stable.
- Fix module autoload for TS4800 and ATH79.
- Correct the IRQ handler for MPC8xxx to use handle_level_irq() as it
(a) reacts to edges not levels and (b) even implements .irq_ack().
We were missing IRQs here.
- Fix the error path for acpi_dev_gpio_irq_get()
- Fix a memory leak in the MXS driver.
- Fix an annoying typo in the STMPE driver.
- Put a dependency on sysfs to the mockup driver"
* tag 'gpio-v4.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
gpio: mpc8xxx: Correct irq handler function
gpio: ath79: Fix module autoload
gpio: ts4800: Fix module autoload
gpio: GPIO_GET_LINEEVENT_IOCTL: Reject invalid line and event flags
gpio: GPIO_GET_LINEHANDLE_IOCTL: Reject invalid line flags
gpio: GPIOHANDLE_GET_LINE_VALUES_IOCTL: Fix information leak
gpio: GPIO_GET_LINEEVENT_IOCTL: Validate line offset
gpio: GPIOHANDLE_GET_LINE_VALUES_IOCTL: Fix information leak
gpio: GPIO_GET_LINEHANDLE_IOCTL: Validate line offset
gpio: GPIO_GET_CHIPINFO_IOCTL: Fix information leak
gpio: GPIO_GET_CHIPINFO_IOCTL: Fix line offset validation
gpio / ACPI: fix returned error from acpi_dev_gpio_irq_get()
gpio: mockup: add sysfs dependency
gpio: stmpe: || vs && typo
gpio: mxs: Unmap region obtained by of_iomap
gpio/board.txt: point to gpiod_set_value
Diffstat (limited to 'drivers/gpio/gpiolib.c')
-rw-r--r-- | drivers/gpio/gpiolib.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0fc3a0d37c8..20e09b7c2de3 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -333,6 +333,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) { @@ -344,6 +351,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]); @@ -444,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) @@ -536,6 +556,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) { @@ -623,6 +647,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; @@ -726,6 +752,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; @@ -823,6 +861,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'; @@ -839,7 +879,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]; |